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
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
26 #include "UpdateMask.h"
28 #include "ObjectMgr.h"
31 #include "SkillExtraItems.h"
33 #include "CreatureAI.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
53 #include "SocialMgr.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())
230 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
233 if(!unitTarget
->IsInWorld())
236 Player
* pTarget
= ((Player
*)unitTarget
);
238 if(pTarget
->isRessurectRequested()) // already have one active request
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() )
253 if(m_spellInfo
->Id
==18788 && unitTarget
->GetTypeId()==TYPEID_UNIT
)
255 uint32 entry
= unitTarget
->GetEntry();
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
265 sLog
.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry
);
269 m_caster
->CastSpell(m_caster
,spellID
,true);
272 if(m_caster
==unitTarget
) // prevent interrupt message
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
)
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
:
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
323 for(std::list
<TargetInfo
>::iterator ihit
= m_UniqueTargetInfo
.begin();ihit
!= m_UniqueTargetInfo
.end();++ihit
)
324 if(ihit
->effectMask
& (1<<effect_idx
))
327 damage
/= count
; // divide to all targets
330 // percent from health with min
331 case 25599: // Thundercrash
333 damage
= unitTarget
->GetHealth() / 2;
342 case SPELLFAMILY_MAGE
:
345 if(m_spellInfo
->SpellFamilyFlags
& 0x20000000LL
)
347 m_caster
->CastSpell(m_caster
,36032,true);
351 case SPELLFAMILY_WARRIOR
:
354 if(m_spellInfo
->SpellFamilyFlags
& 0x40000000000LL
)
356 damage
= uint32(damage
* (m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)) / 100);
359 else if(m_spellInfo
->SpellFamilyFlags
& 0x100000000LL
)
360 damage
+= int32(m_caster
->GetShieldBlockValue());
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);
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);
380 case SPELLFAMILY_DRUID
:
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);
391 else if(m_spellInfo
->SpellFamilyFlags
& 0x0000000000001000LL
)
393 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
) / 100);
396 else if(m_spellInfo
->SpellFamilyFlags
& 0x0010000000000000LL
)
398 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)*0.08f
);
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;
424 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
426 damage
+= (*i
)->GetModifier()->m_amount
;
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
);
446 case SPELLFAMILY_ROGUE
:
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
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() )
468 unitTarget
->RemoveSingleAuraFromStack((*itr
)->GetId(), (*itr
)->GetEffIndex());
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;
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))
498 case SPELLFAMILY_HUNTER
:
501 if((m_spellInfo
->SpellFamilyFlags
& 0x000000002) && m_spellInfo
->SpellVisual
==342)
503 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)*0.2);
506 else if((m_spellInfo
->SpellFamilyFlags
& 0x00000800) && m_spellInfo
->maxLevel
> 0)
508 damage
+= int32(m_caster
->GetTotalAttackPowerValue(RANGED_ATTACK
)*0.15);
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);
523 case SPELLFAMILY_PALADIN
:
525 //Judgement of Vengeance
526 if((m_spellInfo
->SpellFamilyFlags
& 0x800000000LL
) && m_spellInfo
->SpellIconID
==2292)
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())
534 //No damage if the target isn't affected by this
546 if(m_originalCaster
) // m_caster only passive source of cast
547 finalDamage
= m_originalCaster
->SpellNonMeleeDamageLog(unitTarget
, m_spellInfo
->Id
, damage
, m_IsTriggeredSpell
, true);
549 finalDamage
= m_caster
->SpellNonMeleeDamageLog(unitTarget
, m_spellInfo
->Id
, damage
, m_IsTriggeredSpell
, true);
552 switch(m_spellInfo
->SpellFamilyName
)
554 case SPELLFAMILY_WARRIOR
:
557 if(m_spellInfo
->SpellFamilyFlags
& 0x40000000000LL
)
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;
569 sLog
.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo
->Id
);
574 m_caster
->CastSpell(m_caster
,BTAura
,true);
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);
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);
602 void Spell::EffectDummy(uint32 i
)
604 if(!unitTarget
&& !gameObjTarget
&& !itemTarget
)
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
)
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
);
631 case 8213: // Savory Deviate Delight
633 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
640 case 1: spell_id
= (m_caster
->getGender() == GENDER_MALE
? 8219 : 8220); break;
642 case 2: spell_id
= (m_caster
->getGender() == GENDER_MALE
? 8221 : 8222); break;
644 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
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
)
652 ((Creature
*)unitTarget
)->setDeathState(JUST_ALIVED
);
655 case 12162: // Deep wounds
656 case 12850: // (now good common check for this spells)
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;
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;
676 sLog
.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo
->Id
);
680 int32 deepWoundsDotBasePoints0
= int32(damage
/ 4);
681 m_caster
->CastCustomSpell(unitTarget
, 12721, &deepWoundsDotBasePoints0
, NULL
, NULL
, true, NULL
);
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
);
690 case 13120: // net-o-matic
697 uint32 roll
= urand(0, 99);
699 if(roll
< 2) // 2% for 30 sec self root (off-like chance unknown)
701 else if(roll
< 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
706 m_caster
->CastSpell(unitTarget
,spell_id
,true,NULL
);
709 case 13567: // Dummy Trigger
711 // can be used for different aura triggreing, so select by aura
712 if(!m_triggeredByAuraSpell
|| !unitTarget
)
715 switch(m_triggeredByAuraSpell
->Id
)
717 case 26467: // Persistent Shield
718 m_caster
->CastCustomSpell(unitTarget
, 26470, &damage
, NULL
, NULL
, true);
721 sLog
.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell
->Id
);
726 case 14185: // Preparation Rogue
728 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
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
);
750 case 15998: // Capture Worg Pup
751 case 29435: // Capture Female Kaliri Hatchling
753 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
)
756 Creature
* creatureTarget
= (Creature
*)unitTarget
;
757 creatureTarget
->setDeathState(JUST_DIED
);
758 creatureTarget
->RemoveCorpse();
759 creatureTarget
->SetHealth(0); // just for nice GM-mode view
762 case 16589: // Noggenfogger Elixir
764 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
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
);
778 case 17251: // Spirit Healer Res
780 if(!unitTarget
|| !m_originalCaster
)
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
);
791 case 17271: // Test Fetid Skull
793 if(!itemTarget
&& m_caster
->GetTypeId()!=TYPEID_PLAYER
)
796 uint32 spell_id
= roll_chance_i(50) ? 17269 : 17270;
798 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
801 case 20577: // Cannibalize
803 m_caster
->CastSpell(m_caster
,20578,false,NULL
);
805 case 23019: // Crystal Prison Dummy DND
807 if(!unitTarget
|| !unitTarget
->isAlive() || unitTarget
->GetTypeId() != TYPEID_UNIT
|| ((Creature
*)unitTarget
)->isPet())
810 Creature
* creatureTarget
= (Creature
*)unitTarget
;
811 if(creatureTarget
->isPet())
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) )
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");
838 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
839 data
<< uint64(pGameObj
->GetGUID());
840 m_caster
->SendMessageToSet(&data
,true);
844 case 23074: // Arc. Dragonling
845 if (!m_CastItem
) return;
846 m_caster
->CastSpell(m_caster
,19804,true,m_CastItem
);
848 case 23075: // Mithril Mechanical Dragonling
849 if (!m_CastItem
) return;
850 m_caster
->CastSpell(m_caster
,12749,true,m_CastItem
);
852 case 23076: // Mechanical Dragonling
853 if (!m_CastItem
) return;
854 m_caster
->CastSpell(m_caster
,4073,true,m_CastItem
);
856 case 23133: // Gnomish Battle Chicken
857 if (!m_CastItem
) return;
858 m_caster
->CastSpell(m_caster
,13166,true,m_CastItem
);
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);
871 case 23453: // Ultrasafe Transporter: Gadgetzan
872 if ( roll_chance_i(50) ) // success
873 m_caster
->CastSpell(m_caster
,23441,true);
875 m_caster
->CastSpell(m_caster
,23446,true);
877 case 23645: // Hourglass Sand
878 m_caster
->RemoveAurasDueToSpell(23170);
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);
884 case 25860: // Reindeer Transformation
886 if (!m_caster
->HasAuraType(SPELL_AURA_MOUNTED
))
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
904 m_caster
->CastSpell(m_caster
, 25858, true); //60% ground Reindeer
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);
916 case 28730: // Arcane Torrent (Mana)
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)
925 m_caster
->RemoveAurasDueToSpell(28734);
926 int32 bp
= damage
* count
;
927 m_caster
->CastCustomSpell(m_caster
, 28733, &bp
, NULL
, NULL
, true);
931 case 29200: // Purify Helboar Meat
933 if( m_caster
->GetTypeId() != TYPEID_PLAYER
)
936 uint32 spell_id
= roll_chance_i(50) ? 29277 : 29278;
938 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
941 case 29858: // Soulshatter
942 if (unitTarget
&& unitTarget
->GetTypeId() == TYPEID_UNIT
&& unitTarget
->IsHostileTo(m_caster
))
943 m_caster
->CastSpell(unitTarget
,32835,true);
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
);
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
);
957 m_caster
->CastSpell(unitTarget
, 30504, true, m_CastItem
);
959 case 33060: // Make a Wish
961 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
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
);
981 switch(m_caster
->GetAreaId())
983 case 3900: spell_id
= 35743; break;
984 case 3742: spell_id
= 35744; break;
988 m_caster
->CastSpell(m_caster
,spell_id
,true);
991 case 37674: // Chaos Blast
993 m_caster
->CastSpell(unitTarget
,37675,true);
995 case 44875: // Complete Raptor Capture
997 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
)
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
);
1010 case 37573: //Temporal Phase Modulator
1015 TemporarySummon
* tempSummon
= dynamic_cast<TemporarySummon
*>(unitTarget
);
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);
1033 pCreature
->SetHealth(health
);
1036 pCreature
->AI()->AttackStart(m_caster
);
1040 case 34665: //Administer Antidote
1042 if(!unitTarget
|| m_caster
->GetTypeId() != TYPEID_PLAYER
)
1048 TemporarySummon
* tempSummon
= dynamic_cast<TemporarySummon
*>(unitTarget
);
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);
1064 pCreature
->SetHealth(health
);
1065 ((Player
*)m_caster
)->KilledMonster(16992,pCreature
->GetGUID());
1067 if (pCreature
->AI())
1068 pCreature
->AI()->AttackStart(m_caster
);
1072 case 44997: // Converting Sentry
1074 //Converted Sentry Credit
1075 m_caster
->CastSpell(m_caster
, 45009, true);
1078 case 45030: // Impale Emissary
1080 // Emissary of Hate Credit
1081 m_caster
->CastSpell(m_caster
, 45088, true);
1084 case 50243: // Teach Language
1086 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1089 // spell has a 1/3 chance to trigger one of the below
1090 if(roll_chance_i(66))
1092 if(((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
1094 // 1000001 - gnomish binary
1095 m_caster
->CastSpell(m_caster
, 50242, true);
1099 // 01001000 - goblin binary
1100 m_caster
->CastSpell(m_caster
, 50246, true);
1105 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1107 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1110 if(BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround())
1111 bg
->EventPlayerDroppedFlag((Player
*)m_caster
);
1113 m_caster
->CastSpell(m_caster
, 30452, true, NULL
);
1118 //All IconID Check in there
1119 switch(m_spellInfo
->SpellIconID
)
1121 // Berserking (troll racial traits)
1124 uint32 healthPerc
= uint32((float(m_caster
->GetHealth())/m_caster
->GetMaxHealth())*100);
1125 int32 melee_mod
= 10;
1126 if (healthPerc
<= 40)
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
);
1142 case SPELLFAMILY_MAGE
:
1143 switch(m_spellInfo
->Id
)
1145 case 11958: // Cold Snap
1147 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
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
)
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
);
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);
1186 case SPELLFAMILY_WARRIOR
:
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);
1195 if(m_spellInfo
->SpellFamilyFlags
& 0x20000000)
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);
1205 if(m_spellInfo
->Id
==21977) //Warrior's Wrath
1210 m_caster
->CastSpell(unitTarget
,21887,true); // spell mod
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
);
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
);
1243 int32 manaFeedVal
= m_caster
->CalculateSpellDamage(m_spellInfo
,1, m_spellInfo
->EffectBasePoints
[1],m_caster
);
1244 manaFeedVal
= manaFeedVal
* mana
/ 100;
1246 m_caster
->CastCustomSpell(m_caster
,32553,&manaFeedVal
,NULL
,NULL
,true,NULL
);
1249 SendCastResult(SPELL_FAILED_FIZZLE
);
1253 case SPELLFAMILY_PRIEST
:
1254 switch(m_spellInfo
->Id
)
1256 case 28598: // Touch of Weakness triggered spell
1258 if(!unitTarget
|| !m_triggeredByAuraSpell
)
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
1272 sLog
.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell
->Id
);
1275 m_caster
->CastSpell(unitTarget
, spellid
, true, NULL
);
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
);
1292 case SPELLFAMILY_ROGUE
:
1293 switch(m_spellInfo
->Id
)
1295 case 31231: // Cheat Death
1297 m_caster
->CastSpell(m_caster
,45182,true);
1302 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1305 Player
*pCaster
= ((Player
*)m_caster
);
1307 Item
*item
= pCaster
->GetWeaponForAttack(OFF_ATTACK
);
1311 // all poison enchantments is temporary
1312 uint32 enchant_id
= item
->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT
);
1316 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
1320 for (int s
=0;s
<3;s
++)
1322 if(pEnchant
->type
[s
]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
)
1325 SpellEntry
const* combatEntry
= sSpellStore
.LookupEntry(pEnchant
->spellid
[s
]);
1326 if(!combatEntry
|| combatEntry
->Dispel
!= DISPEL_POISON
)
1329 m_caster
->CastSpell(unitTarget
, combatEntry
, true, item
);
1332 m_caster
->CastSpell(unitTarget
, 5940, true);
1337 case SPELLFAMILY_HUNTER
:
1339 if(m_spellInfo
->SpellFamilyFlags
& 0x100000000LL
)
1341 if( !unitTarget
|| !unitTarget
->isAlive())
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)
1358 m_caster
->SpellNonMeleeDamageLog(unitTarget
, m_spellInfo
->Id
, damage
, m_IsTriggeredSpell
, true);
1362 if(m_spellInfo
->SpellFamilyFlags
& 0x00080000000000LL
)
1364 if(m_caster
->getClass()!=CLASS_HUNTER
)
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())
1375 uint32 spell_id
= 0;
1376 switch (m_spellInfo
->Id
)
1378 case 34026: spell_id
= 34027; break; // rank 1
1380 sLog
.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo
->Id
);
1384 pet
->CastSpell(pet
->getVictim(), spell_id
, true);
1388 switch(m_spellInfo
->Id
)
1390 case 23989: //Readiness talent
1392 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
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
);
1414 case 37506: // Scatter Shot
1416 if (m_caster
->GetTypeId()!=TYPEID_PLAYER
)
1419 // break Auto Shot and autohit
1420 m_caster
->InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
1421 m_caster
->AttackStop();
1422 ((Player
*)m_caster
)->SendAttackSwingCancelAttack();
1427 case SPELLFAMILY_PALADIN
:
1428 switch(m_spellInfo
->SpellIconID
)
1430 case 156: // Holy Shock
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;
1446 sLog
.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo
->Id
);
1450 if(m_caster
->IsFriendlyTo(unitTarget
))
1451 m_caster
->CastSpell(unitTarget
, heal
, true, 0);
1453 m_caster
->CastSpell(unitTarget
, hurt
, true, 0);
1457 case 561: // Judgement of command
1462 uint32 spell_id
= m_currentBasePoints
[i
]+1;
1463 SpellEntry
const* spell_proto
= sSpellStore
.LookupEntry(spell_id
);
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
;
1473 mod
->type
= SPELLMOD_PCT
;
1474 mod
->spellId
= m_spellInfo
->Id
;
1476 mod
->lastAffected
= NULL
;
1477 mod
->mask
= 0x0000020000000000LL
;
1480 ((Player
*)m_caster
)->AddSpellMod(mod
, true);
1481 m_caster
->CastSpell(unitTarget
,spell_proto
,true,NULL
);
1483 ((Player
*)m_caster
)->AddSpellMod(mod
, false);
1486 m_caster
->CastSpell(unitTarget
,spell_proto
,true,NULL
);
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
);
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();
1527 for(Unit::AttackerSet::const_iterator aItr
= attackers
.begin(); aItr
!= attackers
.end() && count
< 3; ++aItr
)
1529 if(!roll_chance_f(chance
))
1532 AddUnitTarget((*aItr
), 1);
1535 // now let next effect cast spell at each target.
1538 case 37877: // Blessing of Faith
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);
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
1575 sLog
.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo
->Id
);
1579 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( spell_id
);
1583 sLog
.outError("WORLD: unknown spell id %i\n", spell_id
);
1587 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
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
);
1612 if(m_spellInfo
->Id
== 39610) // Mana-Tide Totem effect
1614 if(!unitTarget
|| unitTarget
->getPowerType() != POWER_MANA
)
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
);
1627 if(PetAura
const* petSpell
= spellmgr
.GetPetAura(m_spellInfo
->Id
))
1629 m_caster
->AddPetAura(petSpell
);
1634 void Spell::EffectTriggerSpellWithValue(uint32 i
)
1636 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1639 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1643 sLog
.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo
->Id
,triggered_spell_id
);
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
);
1658 sLog
.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
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
)
1679 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1682 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1686 sLog
.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
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
];
1698 switch(triggered_spell_id
)
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
)
1711 // get highest rank of the Stealth spell
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
)
1720 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
1724 if (spellInfo
->SpellFamilyName
== SPELLFAMILY_ROGUE
&& spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE_STEALTH
)
1726 spellId
= spellInfo
->Id
;
1731 // no Stealth spell found
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);
1743 case 23770: // Sayge's Dark Fortune of *
1744 // not exist, common cooldown can be implemented in scripts if need.
1746 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1749 const SpellEntry
*spell
= sSpellStore
.LookupEntry(24575);
1753 for (int i
=0; i
< spell
->StackAmount
; ++i
)
1754 m_caster
->CastSpell(unitTarget
,spell
->Id
, true, m_CastItem
, NULL
, m_originalCasterGUID
);
1757 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1760 const SpellEntry
*spell
= sSpellStore
.LookupEntry(26464);
1764 for (int i
=0; i
< spell
->StackAmount
; ++i
)
1765 m_caster
->CastSpell(unitTarget
,spell
->Id
, true, m_CastItem
, NULL
, m_originalCasterGUID
);
1768 // Righteous Defense
1771 m_caster
->CastSpell(unitTarget
, 31790, true,m_CastItem
,NULL
,m_originalCasterGUID
);
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();
1794 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1797 if (Unit
*pet
= m_caster
->GetPet())
1798 pet
->CastSpell(pet
, 28305, true);
1804 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1808 sLog
.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
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() )
1824 // skip spell if weapon not fit to triggered spell
1825 if(!item
->IsFitToSpellRequirements(spellInfo
))
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() )
1838 // skip spell if weapon not fit to triggered spell
1839 if(!item
->IsFitToSpellRequirements(spellInfo
))
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
)
1858 m_caster
->CastSpell(unitTarget
,spellInfo
,true,m_CastItem
,NULL
,m_originalCasterGUID
);
1861 m_TriggerSpells
.push_back(spellInfo
);
1864 void Spell::EffectTriggerMissileSpell(uint32 effect_idx
)
1866 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[effect_idx
];
1869 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1873 sLog
.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo
->Id
,triggered_spell_id
);
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())
1893 switch (m_spellInfo
->EffectImplicitTargetB
[i
])
1895 case TARGET_INNKEEPER_COORDINATES
:
1897 // Only players can teleport to innkeeper
1898 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
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);
1904 case TARGET_TABLE_X_Y_Z_COORDINATES
:
1906 // TODO: Only players can teleport?
1907 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
1909 SpellTargetPosition
const* st
= spellmgr
.GetSpellTargetPosition(m_spellInfo
->Id
);
1912 sLog
.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo
->Id
);
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);
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());
1925 pTarget
= m_caster
->getVictim();
1926 // No target present - 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();
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));
1940 MapManager::Instance().GetMap(mapid
, m_caster
)->CreatureRelocation((Creature
*)unitTarget
, x
, y
, z
, orientation
);
1942 unitTarget
->BuildTeleportAckMsg(&data
, x
, y
, z
, orientation
);
1943 unitTarget
->SendMessageToSet(&data
, false);
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
);
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();
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));
1966 MapManager::Instance().GetMap(mapid
, m_caster
)->CreatureRelocation((Creature
*)unitTarget
, x
, y
, z
, orientation
);
1968 unitTarget
->BuildTeleportAckMsg(&data
, x
, y
, z
, orientation
);
1969 unitTarget
->SendMessageToSet(&data
, false);
1975 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1976 switch ( m_spellInfo
->Id
)
1978 // Dimensional Ripper - Everlook
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);
1987 m_caster
->CastSpell(m_caster
,23449,true);
1991 // Ultrasafe Transporter: Toshley's Station
1994 if ( roll_chance_i(50) ) // 50% success
1996 int32 rand_eff
= urand(1,7);
2000 // soul split - evil
2001 m_caster
->CastSpell(m_caster
,36900,true);
2004 // soul split - good
2005 m_caster
->CastSpell(m_caster
,36901,true);
2008 // Increase the size
2009 m_caster
->CastSpell(m_caster
,36895,true);
2012 // Decrease the size
2013 m_caster
->CastSpell(m_caster
,36893,true);
2018 if (((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
2019 m_caster
->CastSpell(m_caster
,36897,true);
2021 m_caster
->CastSpell(m_caster
,36899,true);
2026 m_caster
->CastSpell(m_caster
,36940,true);
2030 m_caster
->CastSpell(m_caster
,23445,true);
2036 // Dimensional Ripper - Area 52
2039 if ( roll_chance_i(50) ) // 50% success
2041 int32 rand_eff
= urand(1,4);
2045 // soul split - evil
2046 m_caster
->CastSpell(m_caster
,36900,true);
2049 // soul split - good
2050 m_caster
->CastSpell(m_caster
,36901,true);
2053 // Increase the size
2054 m_caster
->CastSpell(m_caster
,36895,true);
2059 if (((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
2060 m_caster
->CastSpell(m_caster
,36897,true);
2062 m_caster
->CastSpell(m_caster
,36899,true);
2072 void Spell::EffectApplyAura(uint32 i
)
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
])
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()) )
2087 Unit
* caster
= m_originalCasterGUID
? m_originalCaster
: m_caster
;
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()))
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;
2119 // found crash at character loading, broken pointer to Aur...
2120 // Aur was deleted in AddAura()...
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
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
)
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
)
2172 Powers drain_power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2176 if(!unitTarget
->isAlive())
2178 if(unitTarget
->getPowerType() != drain_power
)
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
);
2194 if(curPower
< power
)
2195 new_damage
= curPower
;
2199 unitTarget
->ModifyPower(drain_power
,-new_damage
);
2201 if(drain_power
== POWER_MANA
)
2203 float manaMultiplier
= m_spellInfo
->EffectMultipleValue
[i
];
2204 if(manaMultiplier
==0)
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
);
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");
2234 case 23334: // Drop Horde Flag
2235 if(bg->GetTypeID()==BATTLEGROUND_WS)
2236 bg->EventPlayerDroppedFlag((Player*)m_caster);
2237 sLog.outDebug("Drop Horde Flag");
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");
2247 case 23336: // Drop Alliance Flag
2248 if(bg->GetTypeID()==BATTLEGROUND_WS)
2249 bg->EventPlayerDroppedFlag((Player*)m_caster);
2250 sLog.outDebug("Drop Alliance Flag");
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");
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");
2264 if(bg->GetTypeID()==BATTLEGROUND_EY)
2265 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2269 sLog
.outDebug("Unknown spellid %u in BG event", m_spellInfo
->Id
);
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
)
2283 Powers powertype
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2287 if(!unitTarget
->isAlive())
2289 if(unitTarget
->getPowerType()!=powertype
)
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
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
;
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())
2358 sLog
.outError("Target(GUID:" I64FMTD
") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget
->GetGUID());
2364 if(targetAura
->GetSpellProto()->EffectApplyAuraName
[idx
] == SPELL_AURA_PERIODIC_HEAL
)
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
;
2376 addhealth
= caster
->SpellHealingBonus(m_spellInfo
, addhealth
,HEAL
, unitTarget
);
2378 bool crit
= caster
->isSpellCrit(unitTarget
, m_spellInfo
, m_spellSchoolMask
, m_attackType
);
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
2394 uint32 procHealer
= PROC_FLAG_HEAL
;
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
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
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
)
2447 if(!unitTarget
->isAlive())
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
)
2482 Player
* player
= (Player
*)unitTarget
;
2484 uint32 newitemid
= itemtype
;
2485 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( newitemid
);
2488 player
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, NULL
, NULL
);
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
];
2500 num_to_add
= basePoints
+ irand(1, randomPoints
);
2502 num_to_add
= basePoints
+ 1;
2504 else if (pProto
->MaxCount
== 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
);
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
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
)
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
;
2548 // if not created by another reason from full inventory or unique items amount limitation
2549 player
->SendEquipError( msg
, NULL
, NULL
);
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
2562 player
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, NULL
, NULL
);
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
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
2581 BattleGroundTypeId bgType
;
2582 switch(m_spellInfo
->Id
)
2584 case SPELL_AV_MARK_WINNER
:
2585 case SPELL_AV_MARK_LOSER
:
2586 bgType
= BATTLEGROUND_AV
;
2588 case SPELL_WS_MARK_WINNER
:
2589 case SPELL_WS_MARK_LOSER
:
2590 bgType
= BATTLEGROUND_WS
;
2592 case SPELL_AB_MARK_WINNER
:
2593 case SPELL_AB_MARK_LOSER
:
2594 bgType
= BATTLEGROUND_AB
;
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
))
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
)
2635 if(!unitTarget
->isAlive())
2638 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2641 // Some level depends spells
2644 switch (m_spellInfo
->Id
)
2648 level_diff
= m_caster
->getLevel() - 40;
2653 level_diff
= m_caster
->getLevel() - 60;
2658 level_diff
= m_caster
->getLevel() - 60;
2666 damage
-= multipler
* level_diff
;
2671 Powers power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2673 if(unitTarget
->GetMaxPower(power
) == 0)
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
))
2705 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
2706 if (spellInfo
&& (spellInfo
->spellLevel
< m_spellInfo
->spellLevel
|| spellInfo
->spellLevel
> unitTarget
->getLevel()))
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
)
2726 if(!unitTarget
->isAlive())
2729 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2732 Powers power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2734 uint32 maxPower
= unitTarget
->GetMaxPower(power
);
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
;
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
);
2759 case GAMEOBJECT_TYPE_QUESTGIVER
:
2760 // start or end quest
2761 player
->PrepareQuestMenu(guid
);
2762 player
->SendPreparedQuest(guid
);
2765 case GAMEOBJECT_TYPE_SPELL_FOCUS
:
2766 // triggering linked GO
2767 if(uint32 trapEntry
= gameObjTarget
->GetGOInfo()->spellFocus
.linkedTrapId
)
2768 gameObjTarget
->TriggeringLinkedGameObject(trapEntry
,m_caster
);
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
)
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
);
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
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!");
2828 Player
* player
= (Player
*)m_caster
;
2830 LootType loottype
= LOOT_CORPSE
;
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
);
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
);
2863 lockId
= gameObjTarget
->GetLockId();
2864 guid
= gameObjTarget
->GetGUID();
2868 lockId
= itemTarget
->GetProto()->LockID
;
2869 guid
= itemTarget
->GetGUID();
2873 sLog
.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2877 if(!lockId
) // possible case for GO and maybe for items.
2879 SendLoot(guid
, loottype
);
2884 LockEntry
const *lockInfo
= sLockStore
.LookupEntry(lockId
);
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
);
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
);
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
);
2926 reqSkillValue
= lockInfo
->requiredlockskill
;
2928 else if(SkillId
== SKILL_LOCKPICKING
) // apply picklock skill to wrong target
2930 SendCastResult(SPELL_FAILED_BAD_TARGETS
);
2936 loottype
= LOOT_SKINNING
;
2937 if ( player
->GetSkillValue(SkillId
) + spellSkillBonus
< reqSkillValue
)
2939 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL
);
2943 // update skill if really known
2944 uint32 SkillValue
= player
->GetPureSkillValue(SkillId
);
2945 if(SkillValue
) // non only item base skill
2949 // Allow one skill-up until respawned
2950 if ( !gameObjTarget
->IsInSkillupList( player
->GetGUIDLow() ) &&
2951 player
->UpdateGatherSkill(SkillId
, SkillValue
, reqSkillValue
) )
2952 gameObjTarget
->AddToSkillupList( player
->GetGUIDLow() );
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
)
2971 Player
*player
= (Player
*)m_caster
;
2973 // applied only to using item
2977 // ... only to item in own inventory/bank/equip_slot
2978 if(m_CastItem
->GetOwnerGUID()!=player
->GetGUID())
2981 uint32 newitemid
= m_spellInfo
->EffectItemType
[i
];
2985 uint16 pos
= m_CastItem
->GetPos();
2987 Item
*pNewItem
= Item::CreateItem( newitemid
, 1, player
);
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
);
3017 player
->StoreItem( dest
, pNewItem
, true);
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
);
3035 player
->BankItem( dest
, pNewItem
, true);
3039 else if( player
->IsEquipmentPos ( pos
) )
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
);
3053 player
->EquipItem( dest
, pNewItem
, true);
3054 player
->AutoUnequipOffhandIfNeed();
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
)
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
)
3091 if(!unitTarget
->isAlive())
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
);
3107 case SUMMON_TYPE_WILD
:
3108 EffectSummonWild(i
);
3110 case SUMMON_TYPE_DEMON
:
3111 EffectSummonDemon(i
);
3113 case SUMMON_TYPE_SUMMON
:
3116 case SUMMON_TYPE_CRITTER
:
3117 case SUMMON_TYPE_CRITTER2
:
3118 case SUMMON_TYPE_CRITTER3
:
3119 EffectSummonCritter(i
);
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
);
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
:
3135 sLog
.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo
->EffectMiscValueB
[i
]);
3140 void Spell::EffectSummon(uint32 i
)
3142 if(m_caster
->GetPetGUID())
3147 uint32 pet_entry
= m_spellInfo
->EffectMiscValue
[i
];
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
);
3158 spawnCreature
->SetDuration(duration
);
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
;
3172 // Summon in dest location
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
;
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
;
3192 // set timer for unsummon
3193 int32 duration
= GetSpellDuration(m_spellInfo
);
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
)
3239 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3241 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3242 EffectLearnPetSpell(i
);
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
)
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())
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
))
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);
3312 if (roll_chance_i(miss_chance
))
3313 fail_list
.push_back(aur
->GetId());
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
);
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);
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;
3362 sLog
.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo
->Id
);
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())
3402 // target must be OK to do this
3403 if( unitTarget
->hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) )
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
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);
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
)
3430 // victim must be creature and attackable
3431 if( !unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
|| m_caster
->IsFriendlyTo(unitTarget
) )
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
);
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
))
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
];
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
);
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
)
3506 // If dest location if present
3507 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
3509 // Summon 1 unit in dest location
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
3518 m_caster
->GetRandomPoint(center_x
,center_y
,center_z
,radius
,px
,py
,pz
);
3520 // Summon if dest location not present near caster
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
];
3538 // Jewelery statue case (totem like)
3539 if(m_spellInfo
->SpellIconID
==2056)
3541 EffectSummonTotem(i
);
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
);
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
;
3595 // If dest location if present
3596 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
3598 // Summon 1 unit in dest location
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
3607 m_caster
->GetRandomPoint(center_x
,center_y
,center_z
,radius
,px
,py
,pz
);
3609 // Summon if dest location not present near caster
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
;
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
)
3652 if(unitTarget
->isInFlight())
3655 uint32 mapid
= m_caster
->GetMapId();
3656 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
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));
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
)
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
)
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
)
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
)
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
);
3722 // item can be in trade slot and have owner diff. from caster
3723 Player
* item_owner
= itemTarget
->GetOwner();
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
)
3748 Player
* p_caster
= (Player
*)m_caster
;
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
)
3767 case 2: enchant_id
= 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3769 case 4: enchant_id
= 6; break; // 0% [ 7% == 4, 14% == 4]
3770 case 5: enchant_id
= 3025; break; // 20%
3772 case 6: enchant_id
= 1; break; // 0% [ 7% == 6, 14% == 6]
3773 case 7: enchant_id
= 3027; break; // 20%
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%
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%
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%
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%
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%
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%
3804 sLog
.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage
);
3811 sLog
.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo
->Id
,i
);
3815 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
3818 sLog
.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo
->Id
,i
,enchant_id
);
3822 // select enchantment 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
3849 duration
= 3600; // 1 hour
3851 // item can be in trade slot and have owner diff. from caster
3852 Player
* item_owner
= itemTarget
->GetOwner();
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())
3879 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
3882 Creature
* creatureTarget
= (Creature
*)unitTarget
;
3884 if(creatureTarget
->isPet())
3887 if(m_caster
->getClass() == CLASS_HUNTER
)
3889 // cast finish successfully
3890 //SendChannelUpdate(0);
3893 Pet
* pet
= new Pet(HUNTER_PET
);
3895 if(!pet
->CreateBaseAtCreature(creatureTarget
))
3901 creatureTarget
->setDeathState(JUST_DIED
);
3902 creatureTarget
->RemoveCorpse();
3903 creatureTarget
->SetHealth(0); // just for nice GM-mode view
3905 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, m_caster
->GetGUID());
3906 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, m_caster
->GetGUID());
3907 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,m_caster
->getFaction());
3908 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
3910 if(!pet
->InitStatsForLevel(creatureTarget
->getLevel()))
3912 sLog
.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
3917 // prepare visual effect for levelup
3918 pet
->SetUInt32Value(UNIT_FIELD_LEVEL
,creatureTarget
->getLevel()-1);
3920 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
3921 // this enables pet details window (Shift+P)
3922 pet
->AIM_Initialize();
3923 pet
->InitPetCreateSpells();
3924 pet
->SetHealth(pet
->GetMaxHealth());
3926 MapManager::Instance().GetMap(pet
->GetMapId(), pet
)->Add((Creature
*)pet
);
3928 // visual effect for levelup
3929 pet
->SetUInt32Value(UNIT_FIELD_LEVEL
,creatureTarget
->getLevel());
3931 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3933 m_caster
->SetPet(pet
);
3934 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
3935 ((Player
*)m_caster
)->PetSpellInitialize();
3940 void Spell::EffectSummonPet(uint32 i
)
3942 uint32 petentry
= m_spellInfo
->EffectMiscValue
[i
];
3944 Pet
*OldSummon
= m_caster
->GetPet();
3946 // if pet requested type already exist
3949 if(petentry
== 0 || OldSummon
->GetEntry() == petentry
)
3951 // pet in corpse state can't be summoned
3952 if( OldSummon
->isDead() )
3955 MapManager::Instance().GetMap(OldSummon
->GetMapId(), OldSummon
)->Remove((Creature
*)OldSummon
,false);
3956 OldSummon
->SetMapId(m_caster
->GetMapId());
3959 m_caster
->GetClosePoint(px
, py
, pz
, OldSummon
->GetObjectSize());
3961 OldSummon
->Relocate(px
, py
, pz
, OldSummon
->GetOrientation());
3962 MapManager::Instance().GetMap(m_caster
->GetMapId(), m_caster
)->Add((Creature
*)OldSummon
);
3964 if(m_caster
->GetTypeId() == TYPEID_PLAYER
&& OldSummon
->isControlled() )
3966 ((Player
*)m_caster
)->PetSpellInitialize();
3971 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3972 ((Player
*)m_caster
)->RemovePet(OldSummon
,(OldSummon
->getPetType()==HUNTER_PET
? PET_SAVE_AS_DELETED
: PET_SAVE_NOT_IN_SLOT
),false);
3977 Pet
* NewSummon
= new Pet
;
3979 // petentry==0 for hunter "call pet" (current pet summoned if any)
3980 if(NewSummon
->LoadPetFromDB(m_caster
,petentry
))
3982 if(NewSummon
->getPetType()==SUMMON_PET
)
3984 // Remove Demonic Sacrifice auras (known pet)
3985 Unit::AuraList
const& auraClassScripts
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
3986 for(Unit::AuraList::const_iterator itr
= auraClassScripts
.begin();itr
!=auraClassScripts
.end();)
3988 if((*itr
)->GetModifier()->m_miscvalue
==2228)
3990 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
3991 itr
= auraClassScripts
.begin();
4001 // not error in case fail hunter call pet
4008 CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(petentry
);
4012 sLog
.outError("EffectSummonPet: creature entry %u not found.",petentry
);
4017 Map
*map
= m_caster
->GetMap();
4018 uint32 pet_number
= objmgr
.GeneratePetNumber();
4019 if(!NewSummon
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
), map
, petentry
, pet_number
))
4026 m_caster
->GetClosePoint(px
, py
, pz
, NewSummon
->GetObjectSize());
4028 NewSummon
->Relocate(px
, py
, pz
, m_caster
->GetOrientation());
4030 if(!NewSummon
->IsPositionValid())
4032 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());
4037 uint32 petlevel
= m_caster
->getLevel();
4038 NewSummon
->setPetType(SUMMON_PET
);
4040 uint32 faction
= m_caster
->getFaction();
4041 if(m_caster
->GetTypeId() == TYPEID_UNIT
)
4043 if ( ((Creature
*)m_caster
)->isTotem() )
4044 NewSummon
->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE
);
4046 NewSummon
->GetCharmInfo()->SetReactState(REACT_DEFENSIVE
);
4049 NewSummon
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, m_caster
->GetGUID());
4050 NewSummon
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, m_caster
->GetGUID());
4051 NewSummon
->SetUInt32Value(UNIT_NPC_FLAGS
, 0);
4052 NewSummon
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, faction
);
4053 NewSummon
->SetUInt32Value(UNIT_FIELD_BYTES_0
,2048);
4054 NewSummon
->SetUInt32Value(UNIT_FIELD_BYTES_1
,0);
4055 NewSummon
->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP
,time(NULL
));
4056 NewSummon
->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE
,0);
4057 NewSummon
->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP
,1000);
4058 NewSummon
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
4060 NewSummon
->GetCharmInfo()->SetPetNumber(pet_number
, true);
4061 // this enables pet details window (Shift+P)
4063 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4064 NewSummon
->SetUInt32Value(UNIT_FIELD_FLAGS
,UNIT_FLAG_PVP_ATTACKABLE
);
4066 NewSummon
->InitStatsForLevel( petlevel
);
4067 NewSummon
->InitPetCreateSpells();
4069 if(NewSummon
->getPetType()==SUMMON_PET
)
4071 // Remove Demonic Sacrifice auras (new pet)
4072 Unit::AuraList
const& auraClassScripts
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
4073 for(Unit::AuraList::const_iterator itr
= auraClassScripts
.begin();itr
!=auraClassScripts
.end();)
4075 if((*itr
)->GetModifier()->m_miscvalue
==2228)
4077 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
4078 itr
= auraClassScripts
.begin();
4084 // generate new name for summon pet
4085 std::string new_name
=objmgr
.GeneratePetName(petentry
);
4086 if(!new_name
.empty())
4087 NewSummon
->SetName(new_name
);
4089 else if(NewSummon
->getPetType()==HUNTER_PET
)
4090 NewSummon
->SetByteValue(UNIT_FIELD_BYTES_2
, 2, UNIT_RENAME_NOT_ALLOWED
);
4092 NewSummon
->AIM_Initialize();
4093 NewSummon
->SetHealth(NewSummon
->GetMaxHealth());
4094 NewSummon
->SetPower(POWER_MANA
, NewSummon
->GetMaxPower(POWER_MANA
));
4096 map
->Add((Creature
*)NewSummon
);
4098 m_caster
->SetPet(NewSummon
);
4099 sLog
.outDebug("New Pet has guid %u", NewSummon
->GetGUIDLow());
4101 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4103 NewSummon
->SavePetToDB(PET_SAVE_AS_CURRENT
);
4104 ((Player
*)m_caster
)->PetSpellInitialize();
4108 void Spell::EffectLearnPetSpell(uint32 i
)
4110 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
4113 Player
*_player
= (Player
*)m_caster
;
4115 Pet
*pet
= _player
->GetPet();
4121 SpellEntry
const *learn_spellproto
= sSpellStore
.LookupEntry(m_spellInfo
->EffectTriggerSpell
[i
]);
4122 if(!learn_spellproto
)
4125 pet
->SetTP(pet
->m_TrainingPoints
- pet
->GetTPForSpell(learn_spellproto
->Id
));
4126 pet
->learnSpell(learn_spellproto
->Id
);
4128 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
4129 _player
->PetSpellInitialize();
4132 void Spell::EffectTaunt(uint32
/*i*/)
4134 // this effect use before aura Taunt apply for prevent taunt already attacking target
4135 // for spell as marked "non effective at already attacking target"
4136 if(unitTarget
&& unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4138 if(unitTarget
->getVictim()==m_caster
)
4140 SendCastResult(SPELL_FAILED_DONT_REPORT
);
4145 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4146 if(unitTarget
->CanHaveThreatList() && unitTarget
->getThreatManager().getCurrentVictim())
4147 unitTarget
->getThreatManager().addThreat(m_caster
,unitTarget
->getThreatManager().getCurrentVictim()->getThreat());
4150 void Spell::EffectWeaponDmg(uint32 i
)
4154 if(!unitTarget
->isAlive())
4157 // multiple weapon dmg effect workaround
4158 // execute only the last weapon damage
4159 // and handle all effects at once
4160 for (int j
= 0; j
< 3; j
++)
4162 switch(m_spellInfo
->Effect
[j
])
4164 case SPELL_EFFECT_WEAPON_DAMAGE
:
4165 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
:
4166 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG
:
4167 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
:
4168 if (j
< i
) // we must calculate only at last weapon effect
4174 // some spell specific modifiers
4175 bool customBonusDamagePercentMod
= false;
4176 float bonusDamagePercentMod
= 1.0f
; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4177 float weaponDamagePercentMod
= 1.0f
; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4178 float totalDamagePercentMod
= 1.0f
; // applied to final bonus+weapon damage
4179 bool normalized
= false;
4181 int32 spell_bonus
= 0; // bonus specific for spell
4182 switch(m_spellInfo
->SpellFamilyName
)
4184 case SPELLFAMILY_WARRIOR
:
4186 // Whirlwind, single only spell with 2 weapon white damage apply if have
4187 if(m_caster
->GetTypeId()==TYPEID_PLAYER
&& (m_spellInfo
->SpellFamilyFlags
& 0x00000400000000LL
))
4189 if(((Player
*)m_caster
)->GetWeaponForAttack(OFF_ATTACK
,true))
4190 spell_bonus
+= m_caster
->CalculateDamage (OFF_ATTACK
, normalized
);
4192 // Devastate bonus and sunder armor refresh
4193 else if(m_spellInfo
->SpellVisual
== 671 && m_spellInfo
->SpellIconID
== 1508)
4195 customBonusDamagePercentMod
= true;
4196 bonusDamagePercentMod
= 0.0f
; // only applied if auras found
4198 Unit::AuraList
const& list
= unitTarget
->GetAurasByType(SPELL_AURA_MOD_RESISTANCE
);
4199 for(Unit::AuraList::const_iterator itr
=list
.begin();itr
!=list
.end();++itr
)
4201 SpellEntry
const *proto
= (*itr
)->GetSpellProto();
4202 if(proto
->SpellVisual
== 406 && proto
->SpellIconID
== 565)
4204 int32 duration
= GetSpellDuration(proto
);
4205 (*itr
)->SetAuraDuration(duration
);
4206 (*itr
)->UpdateAuraDuration();
4207 bonusDamagePercentMod
+= 1.0f
; // +100%
4213 case SPELLFAMILY_ROGUE
:
4216 if(m_spellInfo
->SpellFamilyFlags
& 0x00000200LL
)
4218 customBonusDamagePercentMod
= true;
4219 bonusDamagePercentMod
= 2.5f
; // 250%
4221 // Mutilate (for each hand)
4222 else if(m_spellInfo
->SpellFamilyFlags
& 0x600000000LL
)
4226 if(unitTarget
->HasAuraState(AURA_STATE_DEADLY_POISON
))
4231 Unit::AuraMap
const& auras
= unitTarget
->GetAuras();
4232 for(Unit::AuraMap::const_iterator itr
= auras
.begin(); itr
!=auras
.end(); ++itr
)
4234 if(itr
->second
->GetSpellProto()->Dispel
== DISPEL_POISON
)
4243 totalDamagePercentMod
*= 1.5f
; // 150% if poisoned
4247 case SPELLFAMILY_PALADIN
:
4249 // Seal of Command - receive benefit from Spell Damage and Healing
4250 if(m_spellInfo
->SpellFamilyFlags
& 0x00000002000000LL
)
4252 spell_bonus
+= int32(0.20f
*m_caster
->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo
)));
4253 spell_bonus
+= int32(0.29f
*m_caster
->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo
), unitTarget
));
4257 case SPELLFAMILY_SHAMAN
:
4259 // Skyshatter Harness item set bonus
4261 if(m_spellInfo
->SpellFamilyFlags
& 0x001000000000LL
)
4263 Unit::AuraList
const& m_OverrideClassScript
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
4264 for(Unit::AuraList::const_iterator i
= m_OverrideClassScript
.begin(); i
!= m_OverrideClassScript
.end(); ++i
)
4266 // Stormstrike AP Buff
4267 if ( (*i
)->GetModifier()->m_miscvalue
== 5634 )
4269 m_caster
->CastSpell(m_caster
,38430,true,NULL
,*i
);
4277 int32 fixed_bonus
= 0;
4278 for (int j
= 0; j
< 3; j
++)
4280 switch(m_spellInfo
->Effect
[j
])
4282 case SPELL_EFFECT_WEAPON_DAMAGE
:
4283 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
:
4284 fixed_bonus
+= CalculateDamage(j
,unitTarget
);
4286 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG
:
4287 fixed_bonus
+= CalculateDamage(j
,unitTarget
);
4290 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
:
4291 weaponDamagePercentMod
*= float(CalculateDamage(j
,unitTarget
)) / 100.0f
;
4293 // applied only to prev.effects fixed damage
4294 if(customBonusDamagePercentMod
)
4295 fixed_bonus
= int32(fixed_bonus
*bonusDamagePercentMod
);
4297 fixed_bonus
= int32(fixed_bonus
*weaponDamagePercentMod
);
4300 break; // not weapon damage effect, just skip
4304 // non-weapon damage
4305 int32 bonus
= spell_bonus
+ fixed_bonus
;
4307 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4311 switch(m_attackType
)
4314 case BASE_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_MAINHAND
; break;
4315 case OFF_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_OFFHAND
; break;
4316 case RANGED_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_RANGED
; break;
4319 float weapon_total_pct
= m_caster
->GetModifierValue(unitMod
, TOTAL_PCT
);
4320 bonus
= int32(bonus
*weapon_total_pct
);
4323 // + weapon damage with applied weapon% dmg to base weapon damage in call
4324 bonus
+= int32(m_caster
->CalculateDamage(m_attackType
, normalized
)*weaponDamagePercentMod
);
4327 bonus
= int32(bonus
*totalDamagePercentMod
);
4329 // prevent negative damage
4330 uint32 eff_damage
= uint32(bonus
> 0 ? bonus
: 0);
4332 const uint32 nohitMask
= HITINFO_ABSORB
| HITINFO_RESIST
| HITINFO_MISS
;
4335 VictimState victimState
= VICTIMSTATE_NORMAL
;
4336 uint32 blocked_dmg
= 0;
4337 uint32 absorbed_dmg
= 0;
4338 uint32 resisted_dmg
= 0;
4339 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
4341 m_caster
->DoAttackDamage(unitTarget
, &eff_damage
, &cleanDamage
, &blocked_dmg
, m_spellSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, m_attackType
, m_spellInfo
, m_IsTriggeredSpell
);
4343 if ((hitInfo
& nohitMask
) && m_attackType
!= RANGED_ATTACK
) // not send ranged miss/etc
4344 m_caster
->SendAttackStateUpdate(hitInfo
& nohitMask
, unitTarget
, 1, m_spellSchoolMask
, eff_damage
, absorbed_dmg
, resisted_dmg
, VICTIMSTATE_NORMAL
, blocked_dmg
);
4346 bool criticalhit
= (hitInfo
& HITINFO_CRITICALHIT
);
4347 m_caster
->SendSpellNonMeleeDamageLog(unitTarget
, m_spellInfo
->Id
, eff_damage
, m_spellSchoolMask
, absorbed_dmg
, resisted_dmg
, false, blocked_dmg
, criticalhit
);
4349 if (eff_damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
4351 eff_damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
4355 cleanDamage
.damage
+= eff_damage
;
4359 // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
4360 m_caster
->DealDamage(unitTarget
, eff_damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, SPELL_SCHOOL_MASK_NORMAL
, NULL
, true);
4363 if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (m_spellInfo
->SpellFamilyFlags
& 0x2000000))
4365 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
4366 ((Player
*)m_caster
)->AddComboPoints(unitTarget
, 1);
4370 if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (m_spellInfo
->SpellFamilyFlags
==0x0000040000000000LL
))
4372 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
4373 ((Player
*)m_caster
)->AddComboPoints(unitTarget
,1);
4377 if(m_attackType
== RANGED_ATTACK
&& m_caster
->GetTypeId() == TYPEID_PLAYER
)
4379 Item
*pItem
= ((Player
*)m_caster
)->GetWeaponForAttack( RANGED_ATTACK
);
4381 // wands don't have ammo
4382 if(!pItem
|| pItem
->IsBroken() || pItem
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_WAND
)
4385 if( pItem
->GetProto()->InventoryType
== INVTYPE_THROWN
)
4387 if(pItem
->GetMaxStackCount()==1)
4389 // decrease durability for non-stackable throw weapon
4390 ((Player
*)m_caster
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED
);
4394 // decrease items amount for stackable throw weapon
4396 ((Player
*)m_caster
)->DestroyItemCount( pItem
, count
, true);
4399 else if(uint32 ammo
= ((Player
*)m_caster
)->GetUInt32Value(PLAYER_AMMO_ID
))
4400 ((Player
*)m_caster
)->DestroyItemCount(ammo
, 1, true);
4404 void Spell::EffectThreat(uint32
/*i*/)
4406 if(!unitTarget
|| !unitTarget
->isAlive() || !m_caster
->isAlive())
4409 if(!unitTarget
->CanHaveThreatList())
4412 unitTarget
->AddThreat(m_caster
, float(damage
));
4415 void Spell::EffectHealMaxHealth(uint32
/*i*/)
4419 if(!unitTarget
->isAlive())
4422 uint32 heal
= m_caster
->GetMaxHealth();
4424 int32 gain
= unitTarget
->ModifyHealth(heal
);
4425 unitTarget
->getHostilRefManager().threatAssist(m_caster
, float(gain
) * 0.5f
, m_spellInfo
);
4427 m_caster
->SendHealSpellLog(unitTarget
, m_spellInfo
->Id
, heal
);
4430 void Spell::EffectInterruptCast(uint32
/*i*/)
4434 if(!unitTarget
->isAlive())
4437 // TODO: not all spells that used this effect apply cooldown at school spells
4438 // also exist case: apply cooldown to interrupted cast only and to all spells
4439 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
4441 if (unitTarget
->m_currentSpells
[i
])
4443 // check if we can interrupt spell
4444 if ( unitTarget
->m_currentSpells
[i
]->m_spellInfo
->InterruptFlags
& SPELL_INTERRUPT_FLAG_INTERRUPT
&& unitTarget
->m_currentSpells
[i
]->m_spellInfo
->PreventionType
== SPELL_PREVENTION_TYPE_SILENCE
)
4446 unitTarget
->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget
->m_currentSpells
[i
]->m_spellInfo
), GetSpellDuration(m_spellInfo
));
4447 unitTarget
->InterruptSpell(i
,false);
4453 void Spell::EffectSummonObjectWild(uint32 i
)
4455 uint32 gameobject_id
= m_spellInfo
->EffectMiscValue
[i
];
4457 GameObject
* pGameObj
= new GameObject
;
4459 WorldObject
* target
= focusObject
;
4464 if(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
4466 x
= m_targets
.m_destX
;
4467 y
= m_targets
.m_destY
;
4468 z
= m_targets
.m_destZ
;
4471 m_caster
->GetClosePoint(x
,y
,z
,DEFAULT_WORLD_OBJECT_SIZE
);
4473 Map
*map
= target
->GetMap();
4475 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), gameobject_id
, map
,
4476 x
, y
, z
, target
->GetOrientation(), 0, 0, 0, 0, 100, 1))
4482 int32 duration
= GetSpellDuration(m_spellInfo
);
4483 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4484 pGameObj
->SetSpellId(m_spellInfo
->Id
);
4486 if(pGameObj
->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP
) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4487 m_caster
->AddGameObject(pGameObj
);
4490 if(pGameObj
->GetMapId() == 489 && pGameObj
->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP
) //WS
4492 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4494 Player
*pl
= (Player
*)m_caster
;
4495 BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround();
4496 if(bg
&& bg
->GetTypeID()==BATTLEGROUND_WS
&& bg
->GetStatus() == STATUS_IN_PROGRESS
)
4498 uint32 team
= ALLIANCE
;
4500 if(pl
->GetTeam() == team
)
4503 ((BattleGroundWS
*)bg
)->SetDroppedFlagGUID(pGameObj
->GetGUID(),team
);
4508 if(pGameObj
->GetMapId() == 566 && pGameObj
->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP
) //EY
4510 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4512 BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround();
4513 if(bg
&& bg
->GetTypeID()==BATTLEGROUND_EY
&& bg
->GetStatus() == STATUS_IN_PROGRESS
)
4515 ((BattleGroundEY
*)bg
)->SetDroppedFlagGUID(pGameObj
->GetGUID());
4520 if(uint32 linkedEntry
= pGameObj
->GetLinkedGameObjectEntry())
4522 GameObject
* linkedGO
= new GameObject
;
4523 if(linkedGO
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), linkedEntry
, map
,
4524 x
, y
, z
, target
->GetOrientation(), 0, 0, 0, 0, 100, 1))
4526 linkedGO
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4527 linkedGO
->SetSpellId(m_spellInfo
->Id
);
4529 m_caster
->AddGameObject(linkedGO
);
4541 void Spell::EffectScriptEffect(uint32 effIndex
)
4543 // TODO: we must implement hunter pet summon at login there (spell 6962)
4546 switch(m_spellInfo
->Id
)
4551 if(!itemTarget
&& m_caster
->GetTypeId()!=TYPEID_PLAYER
)
4554 uint32 spell_id
= 0;
4557 case 1: spell_id
= 8854; break;
4558 default: spell_id
= 8855; break;
4561 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
4565 // Healthstone creating spells
4575 Unit::AuraList
const& mDummyAuras
= unitTarget
->GetAurasByType(SPELL_AURA_DUMMY
);
4576 for(Unit::AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
4578 if((*i
)->GetId() == 18692)
4583 else if((*i
)->GetId() == 18693)
4590 static uint32
const itypes
[6][3] = {
4591 { 5512,19004,19005}, // Minor Healthstone
4592 { 5511,19006,19007}, // Lesser Healthstone
4593 { 5509,19008,19009}, // Healthstone
4594 { 5510,19010,19011}, // Greater Healthstone
4595 { 9421,19012,19013}, // Major Healthstone
4596 {22103,22104,22105} // Master Healthstone
4599 switch(m_spellInfo
->Id
)
4601 case 6201: itemtype
=itypes
[0][rank
];break; // Minor Healthstone
4602 case 6202: itemtype
=itypes
[1][rank
];break; // Lesser Healthstone
4603 case 5699: itemtype
=itypes
[2][rank
];break; // Healthstone
4604 case 11729: itemtype
=itypes
[3][rank
];break; // Greater Healthstone
4605 case 11730: itemtype
=itypes
[4][rank
];break; // Major Healthstone
4606 case 27230: itemtype
=itypes
[5][rank
];break; // Master Healthstone
4610 DoCreateItem( effIndex
, itemtype
);
4613 // Brittle Armor - need remove one 24575 Brittle Armor aura
4615 unitTarget
->RemoveSingleAuraFromStack(24575, 0);
4616 unitTarget
->RemoveSingleAuraFromStack(24575, 1);
4618 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4620 unitTarget
->RemoveSingleAuraFromStack(26464, 0);
4622 // Orb teleport spells
4636 switch(m_spellInfo
->Id
)
4638 case 25140: spellid
= 32571; break;
4639 case 25143: spellid
= 32572; break;
4640 case 25650: spellid
= 30140; break;
4641 case 25652: spellid
= 30141; break;
4642 case 29128: spellid
= 32568; break;
4643 case 29129: spellid
= 32569; break;
4644 case 35376: spellid
= 25649; break;
4645 case 35727: spellid
= 35730; break;
4650 unitTarget
->CastSpell(unitTarget
,spellid
,false);
4654 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4669 if(!unitTarget
|| !unitTarget
->isAlive())
4672 // Onyxia Scale Cloak
4673 if(unitTarget
->GetDummyAura(22683))
4677 m_caster
->CastSpell(unitTarget
, 22682, true);
4682 // Summon Black Qiraji Battle Tank
4688 // Prevent stacking of mounts
4689 unitTarget
->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED
);
4691 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4692 if (unitTarget
->GetAreaId() == 3428)
4693 unitTarget
->CastSpell(unitTarget
, 25863, false);
4695 unitTarget
->CastSpell(unitTarget
, 26655, false);
4698 // Piccolo of the Flaming Fire
4701 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4703 unitTarget
->HandleEmoteCommand(EMOTE_STATE_DANCE
);
4712 unitTarget
->CastSpell(unitTarget
, 28694, true);
4721 // 25% chance of casting a random buff
4722 if(roll_chance_i(75))
4725 // triggered spells are 28703 to 28707
4726 // Note: some sources say, that there was the possibility of
4727 // receiving a debuff. However, this seems to be removed by a patch.
4728 const uint32 spellid
= 28703;
4730 // don't overwrite an existing aura
4731 for(uint8 i
=0; i
<5; i
++)
4732 if(unitTarget
->HasAura(spellid
+i
, 0))
4734 unitTarget
->CastSpell(unitTarget
, spellid
+urand(0, 4), true);
4743 // 25% chance of casting Nightmare Pollen
4744 if(roll_chance_i(75))
4746 unitTarget
->CastSpell(unitTarget
, 28721, true);
4750 // Mirren's Drinking Hat
4754 switch ( urand(1,6) )
4756 case 1: case 2: case 3: item
= 23584; break;// Loch Modan Lager
4757 case 4: case 5: item
= 23585; break;// Stouthammer Lite
4758 case 6: item
= 23586; break;// Aerie Peak Pale Ale
4761 DoCreateItem(effIndex
,item
);
4767 // Removes snares and roots.
4768 uint32 mechanic_mask
= (1<<MECHANIC_ROOT
) | (1<<MECHANIC_SNARE
);
4769 Unit::AuraMap
& Auras
= unitTarget
->GetAuras();
4770 for(Unit::AuraMap::iterator iter
= Auras
.begin(), next
; iter
!= Auras
.end(); iter
= next
)
4774 Aura
*aur
= iter
->second
;
4775 if (!aur
->IsPositive()) //only remove negative spells
4777 // check for mechanic mask
4778 if(GetSpellMechanicMask(aur
->GetSpellProto(), aur
->GetEffIndex()) & mechanic_mask
)
4780 unitTarget
->RemoveAurasDueToSpell(aur
->GetId());
4784 next
= Auras
.begin();
4790 case 41126: // Flame Crash
4795 unitTarget
->CastSpell(unitTarget
, 41131, true);
4798 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4803 unitTarget
->CastSpell(unitTarget
, 44870, true);
4807 // Goblin Weather Machine
4829 unitTarget
->CastSpell(unitTarget
, spellId
, true);
4835 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4838 ((Player
*)unitTarget
)->ModifyMoney(50000000);
4844 if( m_spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
4846 switch(m_spellInfo
->SpellFamilyFlags
)
4851 if(!unitTarget
|| !unitTarget
->isAlive())
4853 uint32 spellId2
= 0;
4855 // all seals have aura dummy
4856 Unit::AuraList
const& m_dummyAuras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
4857 for(Unit::AuraList::const_iterator itr
= m_dummyAuras
.begin(); itr
!= m_dummyAuras
.end(); ++itr
)
4859 SpellEntry
const *spellInfo
= (*itr
)->GetSpellProto();
4861 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4862 if ( !spellInfo
|| !IsSealSpell((*itr
)->GetSpellProto()) || (*itr
)->GetEffIndex() != 2 )
4865 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4866 spellId2
= (*itr
)->GetSpellProto()->EffectBasePoints
[2]+1;
4871 // found, remove seal
4872 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
4874 // Sanctified Judgement
4875 Unit::AuraList
const& m_auras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
4876 for(Unit::AuraList::const_iterator i
= m_auras
.begin(); i
!= m_auras
.end(); ++i
)
4878 if ((*i
)->GetSpellProto()->SpellIconID
== 205 && (*i
)->GetSpellProto()->Attributes
== 0x01D0LL
)
4880 int32 chance
= (*i
)->GetModifier()->m_amount
;
4881 if ( roll_chance_i(chance
) )
4883 int32 mana
= spellInfo
->manaCost
;
4884 if ( Player
* modOwner
= m_caster
->GetSpellModOwner() )
4885 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_COST
, mana
);
4886 mana
= int32(mana
* 0.8f
);
4887 m_caster
->CastCustomSpell(m_caster
,31930,&mana
,NULL
,NULL
,true,NULL
,*i
);
4896 m_caster
->CastSpell(unitTarget
,spellId2
,true);
4902 // normal DB scripted effect
4906 sLog
.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo
->Id
);
4907 sWorld
.ScriptsStart(sSpellScripts
, m_spellInfo
->Id
, m_caster
, unitTarget
);
4910 void Spell::EffectSanctuary(uint32
/*i*/)
4914 //unitTarget->CombatStop();
4916 unitTarget
->CombatStop();
4917 unitTarget
->getHostilRefManager().deleteReferences(); // stop all fighting
4918 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4919 if(m_spellInfo
->SpellFamilyName
== SPELLFAMILY_ROGUE
&& (m_spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE_VANISH
))
4921 ((Player
*)m_caster
)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT
);
4925 void Spell::EffectAddComboPoints(uint32
/*i*/)
4930 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
4936 ((Player
*)m_caster
)->AddComboPoints(unitTarget
, damage
);
4939 void Spell::EffectDuel(uint32 i
)
4941 if(!m_caster
|| !unitTarget
|| m_caster
->GetTypeId() != TYPEID_PLAYER
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4944 Player
*caster
= (Player
*)m_caster
;
4945 Player
*target
= (Player
*)unitTarget
;
4947 // caster or target already have requested duel
4948 if( caster
->duel
|| target
->duel
|| !target
->GetSocial() || target
->GetSocial()->HasIgnore(caster
->GetGUIDLow()) )
4951 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4952 // Don't have to check the target's map since you cannot challenge someone across maps
4953 if( caster
->GetMapId() != 0 && caster
->GetMapId() != 1 && caster
->GetMapId() != 530)
4955 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4959 AreaTableEntry
const* casterAreaEntry
= GetAreaEntryByAreaID(caster
->GetZoneId());
4960 if(casterAreaEntry
&& (casterAreaEntry
->flags
& AREA_FLAG_CAPITAL
) )
4962 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4966 AreaTableEntry
const* targetAreaEntry
= GetAreaEntryByAreaID(target
->GetZoneId());
4967 if(targetAreaEntry
&& (targetAreaEntry
->flags
& AREA_FLAG_CAPITAL
) )
4969 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4973 //CREATE DUEL FLAG OBJECT
4974 GameObject
* pGameObj
= new GameObject
;
4976 uint32 gameobject_id
= m_spellInfo
->EffectMiscValue
[i
];
4978 Map
*map
= m_caster
->GetMap();
4979 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), gameobject_id
, map
,
4980 m_caster
->GetPositionX()+(unitTarget
->GetPositionX()-m_caster
->GetPositionX())/2 ,
4981 m_caster
->GetPositionY()+(unitTarget
->GetPositionY()-m_caster
->GetPositionY())/2 ,
4982 m_caster
->GetPositionZ(),
4983 m_caster
->GetOrientation(), 0, 0, 0, 0, 0, 1))
4989 pGameObj
->SetUInt32Value(GAMEOBJECT_FACTION
, m_caster
->getFaction() );
4990 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel()+1 );
4991 int32 duration
= GetSpellDuration(m_spellInfo
);
4992 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4993 pGameObj
->SetSpellId(m_spellInfo
->Id
);
4995 m_caster
->AddGameObject(pGameObj
);
5000 WorldPacket
data(SMSG_DUEL_REQUESTED
, 16);
5001 data
<< pGameObj
->GetGUID();
5002 data
<< caster
->GetGUID();
5003 caster
->GetSession()->SendPacket(&data
);
5004 target
->GetSession()->SendPacket(&data
);
5007 DuelInfo
*duel
= new DuelInfo
;
5008 duel
->initiator
= caster
;
5009 duel
->opponent
= target
;
5010 duel
->startTime
= 0;
5011 duel
->startTimer
= 0;
5012 caster
->duel
= duel
;
5014 DuelInfo
*duel2
= new DuelInfo
;
5015 duel2
->initiator
= caster
;
5016 duel2
->opponent
= caster
;
5017 duel2
->startTime
= 0;
5018 duel2
->startTimer
= 0;
5019 target
->duel
= duel2
;
5021 caster
->SetUInt64Value(PLAYER_DUEL_ARBITER
,pGameObj
->GetGUID());
5022 target
->SetUInt64Value(PLAYER_DUEL_ARBITER
,pGameObj
->GetGUID());
5025 void Spell::EffectStuck(uint32
/*i*/)
5027 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5030 if(!sWorld
.getConfig(CONFIG_CAST_UNSTUCK
))
5033 Player
* pTarget
= (Player
*)unitTarget
;
5035 sLog
.outDebug("Spell Effect: Stuck");
5036 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());
5038 if(pTarget
->isInFlight())
5041 // homebind location is loaded always
5042 pTarget
->TeleportTo(pTarget
->m_homebindMapId
,pTarget
->m_homebindX
,pTarget
->m_homebindY
,pTarget
->m_homebindZ
,pTarget
->GetOrientation(), (unitTarget
==m_caster
? TELE_TO_SPELL
: 0));
5044 // Stuck spell trigger Hearthstone cooldown
5045 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(8690);
5048 Spell
spell(pTarget
,spellInfo
,true,0);
5049 spell
.SendSpellCooldown();
5052 void Spell::EffectSummonPlayer(uint32
/*i*/)
5054 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5057 // Evil Twin (ignore player summon, but hide this for summoner)
5058 if(unitTarget
->GetDummyAura(23445))
5062 m_caster
->GetClosePoint(x
,y
,z
,unitTarget
->GetObjectSize());
5064 ((Player
*)unitTarget
)->SetSummonPoint(m_caster
->GetMapId(),x
,y
,z
);
5066 WorldPacket
data(SMSG_SUMMON_REQUEST
, 8+4+4);
5067 data
<< uint64(m_caster
->GetGUID()); // summoner guid
5068 data
<< uint32(m_caster
->GetZoneId()); // summoner zone
5069 data
<< uint32(MAX_PLAYER_SUMMON_DELAY
*1000); // auto decline after msecs
5070 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5073 static ScriptInfo
generateActivateCommand()
5076 si
.command
= SCRIPT_COMMAND_ACTIVATE_OBJECT
;
5080 void Spell::EffectActivateObject(uint32 effect_idx
)
5085 static ScriptInfo activateCommand
= generateActivateCommand();
5087 int32 delay_secs
= m_spellInfo
->EffectMiscValue
[effect_idx
];
5089 sWorld
.ScriptCommandStart(activateCommand
, delay_secs
, m_caster
, gameObjTarget
);
5092 void Spell::EffectSummonTotem(uint32 i
)
5095 switch(m_spellInfo
->EffectMiscValueB
[i
])
5097 case SUMMON_TYPE_TOTEM_SLOT1
: slot
= 0; break;
5098 case SUMMON_TYPE_TOTEM_SLOT2
: slot
= 1; break;
5099 case SUMMON_TYPE_TOTEM_SLOT3
: slot
= 2; break;
5100 case SUMMON_TYPE_TOTEM_SLOT4
: slot
= 3; break;
5101 // Battle standard case
5102 case SUMMON_TYPE_TOTEM
: slot
= 254; break;
5103 // jewelery statue case, like totem without slot
5104 case SUMMON_TYPE_GUARDIAN
: slot
= 255; break;
5108 if(slot
< MAX_TOTEM
)
5110 uint64 guid
= m_caster
->m_TotemSlot
[slot
];
5113 Creature
*OldTotem
= ObjectAccessor::GetCreature(*m_caster
, guid
);
5114 if(OldTotem
&& OldTotem
->isTotem())
5115 ((Totem
*)OldTotem
)->UnSummon();
5120 if (m_caster
->GetTypeId()==TYPEID_PLAYER
)
5121 team
= ((Player
*)m_caster
)->GetTeam();
5123 Totem
* pTotem
= new Totem
;
5125 if(!pTotem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), m_caster
->GetMap(), m_spellInfo
->EffectMiscValue
[i
], team
))
5131 float angle
= slot
< MAX_TOTEM
? M_PI
/MAX_TOTEM
- (slot
*2*M_PI
/MAX_TOTEM
) : 0;
5134 m_caster
->GetClosePoint(x
,y
,z
,pTotem
->GetObjectSize(),2.0f
,angle
);
5136 // totem must be at same Z in case swimming caster and etc.
5137 if( fabs( z
- m_caster
->GetPositionZ() ) > 5 )
5138 z
= m_caster
->GetPositionZ();
5140 pTotem
->Relocate(x
, y
, z
, m_caster
->GetOrientation());
5142 if(slot
< MAX_TOTEM
)
5143 m_caster
->m_TotemSlot
[slot
] = pTotem
->GetGUID();
5145 pTotem
->SetOwner(m_caster
->GetGUID());
5146 pTotem
->SetTypeBySummonSpell(m_spellInfo
); // must be after Create call where m_spells initilized
5148 int32 duration
=GetSpellDuration(m_spellInfo
);
5149 if(Player
* modOwner
= m_caster
->GetSpellModOwner())
5150 modOwner
->ApplySpellMod(m_spellInfo
->Id
,SPELLMOD_DURATION
, duration
);
5151 pTotem
->SetDuration(duration
);
5153 if (damage
) // if not spell info, DB values used
5155 pTotem
->SetMaxHealth(damage
);
5156 pTotem
->SetHealth(damage
);
5159 pTotem
->SetUInt32Value(UNIT_CREATED_BY_SPELL
,m_spellInfo
->Id
);
5160 pTotem
->SetFlag(UNIT_FIELD_FLAGS
,UNIT_FLAG_PVP_ATTACKABLE
);
5162 pTotem
->ApplySpellImmune(m_spellInfo
->Id
,IMMUNITY_STATE
,SPELL_AURA_MOD_FEAR
,true);
5163 pTotem
->ApplySpellImmune(m_spellInfo
->Id
,IMMUNITY_STATE
,SPELL_AURA_TRANSFORM
,true);
5165 pTotem
->Summon(m_caster
);
5167 if(slot
< MAX_TOTEM
&& m_caster
->GetTypeId() == TYPEID_PLAYER
)
5169 WorldPacket
data(SMSG_TOTEM_CREATED
, 1+8+4+4);
5170 data
<< uint8(slot
);
5171 data
<< uint64(pTotem
->GetGUID());
5172 data
<< uint32(duration
);
5173 data
<< uint32(m_spellInfo
->Id
);
5174 ((Player
*)m_caster
)->SendDirectMessage(&data
);
5178 void Spell::EffectEnchantHeldItem(uint32 i
)
5180 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5181 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5184 Player
* item_owner
= (Player
*)unitTarget
;
5185 Item
* item
= item_owner
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5191 if(!item
->IsEquipped())
5194 if (m_spellInfo
->EffectMiscValue
[i
])
5196 uint32 enchant_id
= m_spellInfo
->EffectMiscValue
[i
];
5197 int32 duration
= GetSpellDuration(m_spellInfo
); //Try duration index first ..
5199 duration
= m_currentBasePoints
[i
]+1; //Base points after ..
5201 duration
= 10; //10 seconds for enchants which don't have listed duration
5203 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
5207 // Always go to temp enchantment slot
5208 EnchantmentSlot slot
= TEMP_ENCHANTMENT_SLOT
;
5210 // Enchantment will not be applied if a different one already exists
5211 if(item
->GetEnchantmentId(slot
) && item
->GetEnchantmentId(slot
) != enchant_id
)
5214 // Apply the temporary enchantment
5215 item
->SetEnchantment(slot
, enchant_id
, duration
*1000, 0);
5216 item_owner
->ApplyEnchantment(item
,slot
,true);
5220 void Spell::EffectDisEnchant(uint32
/*i*/)
5222 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5225 Player
* p_caster
= (Player
*)m_caster
;
5226 if(!itemTarget
|| !itemTarget
->GetProto()->DisenchantID
)
5229 p_caster
->UpdateCraftSkill(m_spellInfo
->Id
);
5231 ((Player
*)m_caster
)->SendLoot(itemTarget
->GetGUID(),LOOT_DISENCHANTING
);
5233 // item will be removed at disenchanting end
5236 void Spell::EffectInebriate(uint32
/*i*/)
5238 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5241 Player
*player
= (Player
*)unitTarget
;
5242 uint16 currentDrunk
= player
->GetDrunkValue();
5243 uint16 drunkMod
= damage
* 256;
5244 if (currentDrunk
+ drunkMod
> 0xFFFF)
5245 currentDrunk
= 0xFFFF;
5247 currentDrunk
+= drunkMod
;
5248 player
->SetDrunkValue(currentDrunk
, m_CastItem
?m_CastItem
->GetEntry():0);
5251 void Spell::EffectFeedPet(uint32 i
)
5253 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5256 Player
*_player
= (Player
*)m_caster
;
5261 Pet
*pet
= _player
->GetPet();
5268 int32 benefit
= pet
->GetCurrentFoodBenefitLevel(itemTarget
->GetProto()->ItemLevel
);
5273 _player
->DestroyItemCount(itemTarget
,count
,true);
5274 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5276 m_caster
->CastCustomSpell(m_caster
,m_spellInfo
->EffectTriggerSpell
[i
],&benefit
,NULL
,NULL
,true);
5279 void Spell::EffectDismissPet(uint32
/*i*/)
5281 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5284 Pet
* pet
= m_caster
->GetPet();
5286 // not let dismiss dead pet
5287 if(!pet
||!pet
->isAlive())
5290 ((Player
*)m_caster
)->RemovePet(pet
,PET_SAVE_NOT_IN_SLOT
);
5293 void Spell::EffectSummonObject(uint32 i
)
5295 uint32 go_id
= m_spellInfo
->EffectMiscValue
[i
];
5298 switch(m_spellInfo
->Effect
[i
])
5300 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1
: slot
= 0; break;
5301 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2
: slot
= 1; break;
5302 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3
: slot
= 2; break;
5303 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4
: slot
= 3; break;
5307 uint64 guid
= m_caster
->m_ObjectSlot
[slot
];
5310 GameObject
* obj
= NULL
;
5312 obj
= ObjectAccessor::GetGameObject(*m_caster
, guid
);
5314 if(obj
) obj
->Delete();
5315 m_caster
->m_ObjectSlot
[slot
] = 0;
5318 GameObject
* pGameObj
= new GameObject
;
5320 float rot2
= sin(m_caster
->GetOrientation()/2);
5321 float rot3
= cos(m_caster
->GetOrientation()/2);
5324 // If dest location if present
5325 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5327 x
= m_targets
.m_destX
;
5328 y
= m_targets
.m_destY
;
5329 z
= m_targets
.m_destZ
;
5331 // Summon in random point all other units if location present
5333 m_caster
->GetClosePoint(x
,y
,z
,DEFAULT_WORLD_OBJECT_SIZE
);
5335 Map
*map
= m_caster
->GetMap();
5336 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), go_id
, map
, x
, y
, z
, m_caster
->GetOrientation(), 0, 0, rot2
, rot3
, 0, 1))
5342 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
,m_caster
->getLevel());
5343 int32 duration
= GetSpellDuration(m_spellInfo
);
5344 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
5345 pGameObj
->SetSpellId(m_spellInfo
->Id
);
5346 m_caster
->AddGameObject(pGameObj
);
5349 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
5350 data
<< pGameObj
->GetGUID();
5351 m_caster
->SendMessageToSet(&data
,true);
5353 m_caster
->m_ObjectSlot
[slot
] = pGameObj
->GetGUID();
5356 void Spell::EffectResurrect(uint32 i
)
5360 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5363 if(unitTarget
->isAlive())
5365 if(!unitTarget
->IsInWorld())
5368 switch (m_spellInfo
->Id
)
5370 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5372 if (roll_chance_i(67))
5374 m_caster
->CastSpell(m_caster
, 8338, true, m_CastItem
);
5378 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5380 if (roll_chance_i(50))
5382 m_caster
->CastSpell(m_caster
, 23055, true, m_CastItem
);
5390 Player
* pTarget
= ((Player
*)unitTarget
);
5392 if(pTarget
->isRessurectRequested()) // already have one active request
5395 uint32 health
= pTarget
->GetMaxHealth() * damage
/ 100;
5396 uint32 mana
= pTarget
->GetMaxPower(POWER_MANA
) * damage
/ 100;
5398 pTarget
->setResurrectRequestData(m_caster
->GetGUID(), m_caster
->GetMapId(), m_caster
->GetPositionX(), m_caster
->GetPositionY(), m_caster
->GetPositionZ(), health
, mana
);
5399 SendResurrectRequest(pTarget
);
5402 void Spell::EffectAddExtraAttacks(uint32
/*i*/)
5404 if(!unitTarget
|| !unitTarget
->isAlive())
5407 if( unitTarget
->m_extraAttacks
)
5410 unitTarget
->m_extraAttacks
= damage
;
5413 void Spell::EffectParry(uint32
/*i*/)
5415 if (unitTarget
->GetTypeId() == TYPEID_PLAYER
)
5417 ((Player
*)unitTarget
)->SetCanParry(true);
5421 void Spell::EffectBlock(uint32
/*i*/)
5423 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5426 ((Player
*)unitTarget
)->SetCanBlock(true);
5429 void Spell::EffectMomentMove(uint32 i
)
5431 if(unitTarget
->isInFlight())
5434 if( m_spellInfo
->rangeIndex
== 1) //self range
5436 uint32 mapid
= m_caster
->GetMapId();
5437 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
5441 unitTarget
->GetClosePoint(fx
,fy
,fz
,unitTarget
->GetObjectSize(),dis
);
5443 unitTarget
->GetPosition(ox
,oy
,oz
);
5445 float fx2
,fy2
,fz2
; // getObjectHitPos overwrite last args in any result case
5446 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid
, ox
,oy
,oz
+0.5, fx
,fy
,oz
+0.5,fx2
,fy2
,fz2
, -0.5))
5451 unitTarget
->UpdateGroundPositionZ(fx
,fy
,fz
);
5454 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
5455 ((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));
5457 MapManager::Instance().GetMap(mapid
, unitTarget
)->CreatureRelocation((Creature
*)unitTarget
, fx
, fy
, fz
, unitTarget
->GetOrientation());
5461 void Spell::EffectReputation(uint32 i
)
5463 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5466 Player
*_player
= (Player
*)unitTarget
;
5468 int32 rep_change
= m_currentBasePoints
[i
]+1; // field store reputation change -1
5470 uint32 faction_id
= m_spellInfo
->EffectMiscValue
[i
];
5472 FactionEntry
const* factionEntry
= sFactionStore
.LookupEntry(faction_id
);
5477 _player
->ModifyFactionReputation(factionEntry
,rep_change
);
5480 void Spell::EffectQuestComplete(uint32 i
)
5482 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5485 Player
*_player
= (Player
*)m_caster
;
5487 uint32 quest_id
= m_spellInfo
->EffectMiscValue
[i
];
5488 _player
->AreaExploredOrEventHappens(quest_id
);
5491 void Spell::EffectSelfResurrect(uint32 i
)
5493 if(!unitTarget
|| unitTarget
->isAlive())
5495 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5497 if(!unitTarget
->IsInWorld())
5506 health
= uint32(-damage
);
5507 mana
= m_spellInfo
->EffectMiscValue
[i
];
5512 health
= uint32(damage
/100.0f
*unitTarget
->GetMaxHealth());
5513 if(unitTarget
->GetMaxPower(POWER_MANA
) > 0)
5514 mana
= uint32(damage
/100.0f
*unitTarget
->GetMaxPower(POWER_MANA
));
5517 Player
*plr
= ((Player
*)unitTarget
);
5518 plr
->ResurrectPlayer(0.0f
);
5520 plr
->SetHealth( health
);
5521 plr
->SetPower(POWER_MANA
, mana
);
5522 plr
->SetPower(POWER_RAGE
, 0 );
5523 plr
->SetPower(POWER_ENERGY
, plr
->GetMaxPower(POWER_ENERGY
) );
5525 plr
->SpawnCorpseBones();
5530 void Spell::EffectSkinning(uint32
/*i*/)
5532 if(unitTarget
->GetTypeId() != TYPEID_UNIT
)
5534 if(!m_caster
|| m_caster
->GetTypeId() != TYPEID_PLAYER
)
5537 Creature
* creature
= (Creature
*) unitTarget
;
5538 int32 targetLevel
= creature
->getLevel();
5541 if(creature
->GetCreatureInfo()->flag1
& 256)
5542 skill
= SKILL_HERBALISM
; // special case
5543 else if(creature
->GetCreatureInfo()->flag1
& 512)
5544 skill
= SKILL_MINING
; // special case
5546 skill
= SKILL_SKINNING
; // normal case
5548 ((Player
*)m_caster
)->SendLoot(creature
->GetGUID(),LOOT_SKINNING
);
5549 creature
->RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
5551 int32 reqValue
= targetLevel
< 10 ? 0 : targetLevel
< 20 ? (targetLevel
-10)*10 : targetLevel
*5;
5553 int32 skillValue
= ((Player
*)m_caster
)->GetPureSkillValue(skill
);
5555 // Double chances for elites
5556 ((Player
*)m_caster
)->UpdateGatherSkill(skill
, skillValue
, reqValue
, creature
->isElite() ? 2 : 1 );
5559 void Spell::EffectCharge(uint32
/*i*/)
5561 if(!unitTarget
|| !m_caster
)
5565 unitTarget
->GetContactPoint(m_caster
, x
, y
, z
);
5566 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5567 ((Creature
*)unitTarget
)->StopMoving();
5569 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5570 m_caster
->SendMonsterMove(x
, y
, z
, 0, MOVEMENTFLAG_WALK_MODE
, 1);
5572 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5573 MapManager::Instance().GetMap(m_caster
->GetMapId(), m_caster
)->CreatureRelocation((Creature
*)m_caster
,x
,y
,z
,m_caster
->GetOrientation());
5575 // not all charge effects used in negative spells
5576 if ( !IsPositiveSpell(m_spellInfo
->Id
))
5577 m_caster
->Attack(unitTarget
,true);
5580 void Spell::EffectSummonCritter(uint32 i
)
5582 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5584 Player
* player
= (Player
*)m_caster
;
5586 uint32 pet_entry
= m_spellInfo
->EffectMiscValue
[i
];
5590 Pet
* old_critter
= player
->GetMiniPet();
5592 // for same pet just despawn
5593 if(old_critter
&& old_critter
->GetEntry() == pet_entry
)
5595 player
->RemoveMiniPet();
5599 // despawn old pet before summon new
5601 player
->RemoveMiniPet();
5604 Pet
* critter
= new Pet(MINI_PET
);
5606 Map
*map
= m_caster
->GetMap();
5607 uint32 pet_number
= objmgr
.GeneratePetNumber();
5608 if(!critter
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
),
5609 map
, pet_entry
, pet_number
))
5611 sLog
.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo
->Id
, pet_entry
);
5617 // If dest location if present
5618 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5620 x
= m_targets
.m_destX
;
5621 y
= m_targets
.m_destY
;
5622 z
= m_targets
.m_destZ
;
5624 // Summon if dest location not present near caster
5626 m_caster
->GetClosePoint(x
,y
,z
,critter
->GetObjectSize());
5628 critter
->Relocate(x
,y
,z
,m_caster
->GetOrientation());
5630 if(!critter
->IsPositionValid())
5632 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());
5637 critter
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
,m_caster
->GetGUID());
5638 critter
->SetUInt64Value(UNIT_FIELD_CREATEDBY
,m_caster
->GetGUID());
5639 critter
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,m_caster
->getFaction());
5640 critter
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
5642 critter
->AIM_Initialize();
5643 critter
->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5644 critter
->SetMaxHealth(1);
5645 critter
->SetHealth(1);
5646 critter
->SetLevel(1);
5648 // set timer for unsummon
5649 int32 duration
= GetSpellDuration(m_spellInfo
);
5651 critter
->SetDuration(duration
);
5653 std::string name
= player
->GetName();
5654 name
.append(petTypeSuffix
[critter
->getPetType()]);
5655 critter
->SetName( name
);
5656 player
->SetMiniPet(critter
);
5658 map
->Add((Creature
*)critter
);
5661 void Spell::EffectKnockBack(uint32 i
)
5663 if(!unitTarget
|| !m_caster
)
5666 // Effect only works on players
5667 if(unitTarget
->GetTypeId()!=TYPEID_PLAYER
)
5670 float vsin
= sin(m_caster
->GetAngle(unitTarget
));
5671 float vcos
= cos(m_caster
->GetAngle(unitTarget
));
5673 WorldPacket
data(SMSG_MOVE_KNOCK_BACK
, (8+4+4+4+4+4));
5674 data
.append(unitTarget
->GetPackGUID());
5675 data
<< uint32(0); // Sequence
5676 data
<< float(vcos
); // x direction
5677 data
<< float(vsin
); // y direction
5678 data
<< float(m_spellInfo
->EffectMiscValue
[i
])/10; // Horizontal speed
5679 data
<< float(damage
/-10); // Z Movement speed (vertical)
5681 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5684 void Spell::EffectSendTaxi(uint32 i
)
5686 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5689 TaxiPathEntry
const* entry
= sTaxiPathStore
.LookupEntry(m_spellInfo
->EffectMiscValue
[i
]);
5693 std::vector
<uint32
> nodes
;
5696 nodes
[0] = entry
->from
;
5697 nodes
[1] = entry
->to
;
5700 switch(m_spellInfo
->Id
)
5702 case 31606: //Stormcrow Amulet
5705 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5706 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5707 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5710 case 34905: //Stealth Flight
5715 ((Player
*)unitTarget
)->ActivateTaxiPathTo(nodes
,mountid
);
5719 void Spell::EffectPlayerPull(uint32 i
)
5721 if(!unitTarget
|| !m_caster
)
5724 // Effect only works on players
5725 if(unitTarget
->GetTypeId()!=TYPEID_PLAYER
)
5728 float vsin
= sin(unitTarget
->GetAngle(m_caster
));
5729 float vcos
= cos(unitTarget
->GetAngle(m_caster
));
5731 WorldPacket
data(SMSG_MOVE_KNOCK_BACK
, (8+4+4+4+4+4));
5732 data
.append(unitTarget
->GetPackGUID());
5733 data
<< uint32(0); // Sequence
5734 data
<< float(vcos
); // x direction
5735 data
<< float(vsin
); // y direction
5737 data
<< float(damage
? damage
: unitTarget
->GetDistance2d(m_caster
));
5738 data
<< float(m_spellInfo
->EffectMiscValue
[i
])/-10; // Z Movement speed
5740 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5743 void Spell::EffectDispelMechanic(uint32 i
)
5748 uint32 mechanic
= m_spellInfo
->EffectMiscValue
[i
];
5750 Unit::AuraMap
& Auras
= unitTarget
->GetAuras();
5751 for(Unit::AuraMap::iterator iter
= Auras
.begin(), next
; iter
!= Auras
.end(); iter
= next
)
5755 SpellEntry
const *spell
= sSpellStore
.LookupEntry(iter
->second
->GetSpellProto()->Id
);
5756 if(spell
->Mechanic
== mechanic
|| spell
->EffectMechanic
[iter
->second
->GetEffIndex()] == mechanic
)
5758 unitTarget
->RemoveAurasDueToSpell(spell
->Id
);
5762 next
= Auras
.begin();
5768 void Spell::EffectSummonDeadPet(uint32
/*i*/)
5770 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5772 Player
*_player
= (Player
*)m_caster
;
5773 Pet
*pet
= _player
->GetPet();
5780 pet
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, 0);
5781 pet
->RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
5782 pet
->setDeathState( ALIVE
);
5783 pet
->clearUnitState(UNIT_STAT_ALL_STATE
);
5784 pet
->SetHealth( uint32(pet
->GetMaxHealth()*(float(damage
)/100)));
5786 pet
->AIM_Initialize();
5788 _player
->PetSpellInitialize();
5789 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
5792 void Spell::EffectDestroyAllTotems(uint32
/*i*/)
5795 for(int slot
= 0; slot
< MAX_TOTEM
; ++slot
)
5797 if(!m_caster
->m_TotemSlot
[slot
])
5800 Creature
* totem
= ObjectAccessor::GetCreature(*m_caster
,m_caster
->m_TotemSlot
[slot
]);
5801 if(totem
&& totem
->isTotem())
5803 uint32 spell_id
= totem
->GetUInt32Value(UNIT_CREATED_BY_SPELL
);
5804 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(spell_id
);
5806 mana
+= spellInfo
->manaCost
* damage
/ 100;
5807 ((Totem
*)totem
)->UnSummon();
5811 int32 gain
= m_caster
->ModifyPower(POWER_MANA
,int32(mana
));
5812 m_caster
->SendEnergizeSpellLog(m_caster
, m_spellInfo
->Id
, gain
, POWER_MANA
);
5815 void Spell::EffectDurabilityDamage(uint32 i
)
5817 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5820 int32 slot
= m_spellInfo
->EffectMiscValue
[i
];
5822 // FIXME: some spells effects have value -1/-2
5823 // Possibly its mean -1 all player equipped items and -2 all items
5826 ((Player
*)unitTarget
)->DurabilityPointsLossAll(damage
,(slot
< -1));
5830 // invalid slot value
5831 if(slot
>= INVENTORY_SLOT_BAG_END
)
5834 if(Item
* item
= ((Player
*)unitTarget
)->GetItemByPos(INVENTORY_SLOT_BAG_0
,slot
))
5835 ((Player
*)unitTarget
)->DurabilityPointsLoss(item
,damage
);
5838 void Spell::EffectDurabilityDamagePCT(uint32 i
)
5840 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5843 int32 slot
= m_spellInfo
->EffectMiscValue
[i
];
5845 // FIXME: some spells effects have value -1/-2
5846 // Possibly its mean -1 all player equipped items and -2 all items
5849 ((Player
*)unitTarget
)->DurabilityLossAll(double(damage
)/100.0f
,(slot
< -1));
5853 // invalid slot value
5854 if(slot
>= INVENTORY_SLOT_BAG_END
)
5860 if(Item
* item
= ((Player
*)unitTarget
)->GetItemByPos(INVENTORY_SLOT_BAG_0
,slot
))
5861 ((Player
*)unitTarget
)->DurabilityLoss(item
,double(damage
)/100.0f
);
5864 void Spell::EffectModifyThreatPercent(uint32
/*effIndex*/)
5869 unitTarget
->getThreatManager().modifyThreatPercent(m_caster
, damage
);
5872 void Spell::EffectTransmitted(uint32 effIndex
)
5874 uint32 name_id
= m_spellInfo
->EffectMiscValue
[effIndex
];
5876 GameObjectInfo
const* goinfo
= objmgr
.GetGameObjectInfo(name_id
);
5880 sLog
.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id
, m_spellInfo
->Id
);
5886 if(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5888 fx
= m_targets
.m_destX
;
5889 fy
= m_targets
.m_destY
;
5890 fz
= m_targets
.m_destZ
;
5892 //FIXME: this can be better check for most objects but still hack
5893 else if(m_spellInfo
->EffectRadiusIndex
[effIndex
] && m_spellInfo
->speed
==0)
5895 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[effIndex
]));
5896 m_caster
->GetClosePoint(fx
,fy
,fz
,DEFAULT_WORLD_OBJECT_SIZE
, dis
);
5900 float min_dis
= GetSpellMinRange(sSpellRangeStore
.LookupEntry(m_spellInfo
->rangeIndex
));
5901 float max_dis
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(m_spellInfo
->rangeIndex
));
5902 float dis
= rand_norm() * (max_dis
- min_dis
) + min_dis
;
5904 m_caster
->GetClosePoint(fx
,fy
,fz
,DEFAULT_WORLD_OBJECT_SIZE
, dis
);
5907 Map
*cMap
= m_caster
->GetMap();
5909 if(goinfo
->type
==GAMEOBJECT_TYPE_FISHINGNODE
)
5911 if ( !cMap
->IsInWater(fx
,fy
,fz
-0.5f
)) // Hack to prevent fishing bobber from failing to land on fishing hole
5912 { // but this is not proper, we really need to ignore not materialized objects
5913 SendCastResult(SPELL_FAILED_NOT_HERE
);
5914 SendChannelUpdate(0);
5918 // replace by water level in this case
5919 fz
= cMap
->GetWaterLevel(fx
,fy
);
5921 // if gameobject is summoning object, it should be spawned right on caster's position
5922 else if(goinfo
->type
==GAMEOBJECT_TYPE_SUMMONING_RITUAL
)
5924 m_caster
->GetPosition(fx
,fy
,fz
);
5927 GameObject
* pGameObj
= new GameObject
;
5929 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), name_id
, cMap
,
5930 fx
, fy
, fz
, m_caster
->GetOrientation(), 0, 0, 0, 0, 100, 1))
5936 int32 duration
= GetSpellDuration(m_spellInfo
);
5938 switch(goinfo
->type
)
5940 case GAMEOBJECT_TYPE_FISHINGNODE
:
5942 m_caster
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
,pGameObj
->GetGUID());
5944 pGameObj
->SetFloatValue(GAMEOBJECT_ROTATION
+ 2, 0.88431775569915771 );
5946 pGameObj
->SetFloatValue(GAMEOBJECT_ROTATION
+ 3, -0.4668855369091033 );
5947 m_caster
->AddGameObject(pGameObj
); // will removed at spell cancel
5949 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5950 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5954 case 0: lastSec
= 3; break;
5955 case 1: lastSec
= 7; break;
5956 case 2: lastSec
= 13; break;
5957 case 3: lastSec
= 17; break;
5960 duration
= duration
- lastSec
*1000 + FISHING_BOBBER_READY_TIME
*1000;
5963 case GAMEOBJECT_TYPE_SUMMONING_RITUAL
:
5965 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
5967 pGameObj
->AddUniqueUse((Player
*)m_caster
);
5968 m_caster
->AddGameObject(pGameObj
); // will removed at spell cancel
5972 case GAMEOBJECT_TYPE_FISHINGHOLE
:
5973 case GAMEOBJECT_TYPE_CHEST
:
5980 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
5982 pGameObj
->SetOwnerGUID(m_caster
->GetGUID() );
5984 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel() );
5985 pGameObj
->SetSpellId(m_spellInfo
->Id
);
5987 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
5988 //m_caster->AddGameObject(pGameObj);
5989 //m_ObjToDel.push_back(pGameObj);
5991 cMap
->Add(pGameObj
);
5993 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
5994 data
<< uint64(pGameObj
->GetGUID());
5995 m_caster
->SendMessageToSet(&data
,true);
5997 if(uint32 linkedEntry
= pGameObj
->GetLinkedGameObjectEntry())
5999 GameObject
* linkedGO
= new GameObject
;
6000 if(linkedGO
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), linkedEntry
, cMap
,
6001 fx
, fy
, fz
, m_caster
->GetOrientation(), 0, 0, 0, 0, 100, 1))
6003 linkedGO
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
6004 linkedGO
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel() );
6005 linkedGO
->SetSpellId(m_spellInfo
->Id
);
6006 linkedGO
->SetOwnerGUID(m_caster
->GetGUID() );
6008 MapManager::Instance().GetMap(linkedGO
->GetMapId(), linkedGO
)->Add(linkedGO
);
6019 void Spell::EffectProspecting(uint32
/*i*/)
6021 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
6024 Player
* p_caster
= (Player
*)m_caster
;
6025 if(!itemTarget
|| !(itemTarget
->GetProto()->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
))
6028 if(itemTarget
->GetCount() < 5)
6031 if( sWorld
.getConfig(CONFIG_SKILL_PROSPECTING
))
6033 uint32 SkillValue
= p_caster
->GetPureSkillValue(SKILL_JEWELCRAFTING
);
6034 uint32 reqSkillValue
= itemTarget
->GetProto()->RequiredSkillRank
;
6035 p_caster
->UpdateGatherSkill(SKILL_JEWELCRAFTING
, SkillValue
, reqSkillValue
);
6038 ((Player
*)m_caster
)->SendLoot(itemTarget
->GetGUID(), LOOT_PROSPECTING
);
6041 void Spell::EffectSkill(uint32
/*i*/)
6043 sLog
.outDebug("WORLD: SkillEFFECT");
6046 void Spell::EffectSummonDemon(uint32 i
)
6048 float px
= m_targets
.m_destX
;
6049 float py
= m_targets
.m_destY
;
6050 float pz
= m_targets
.m_destZ
;
6052 Creature
* Charmed
= m_caster
->SummonCreature(m_spellInfo
->EffectMiscValue
[i
], px
, py
, pz
, m_caster
->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
,3600000);
6056 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6057 Charmed
->SetLevel(m_caster
->getLevel());
6059 // TODO: Add damage/mana/hp according to level
6061 if (m_spellInfo
->EffectMiscValue
[i
] == 89) // Inferno summon
6063 // Enslave demon effect, without mana cost and cooldown
6064 m_caster
->CastSpell(Charmed
, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6067 Charmed
->CastSpell(Charmed
, 22703, true, 0);
6071 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6072 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6073 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6074 This is why we use a half sec delay between the visual effect and the resurrection itself */
6075 void Spell::EffectSpiritHeal(uint32
/*i*/)
6078 if(!unitTarget || unitTarget->isAlive())
6080 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6082 if(!unitTarget->IsInWorld())
6085 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6086 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6087 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6088 ((Player*)unitTarget)->SpawnCorpseBones();
6092 // remove insignia spell effect
6093 void Spell::EffectSkinPlayerCorpse(uint32
/*i*/)
6095 sLog
.outDebug("Effect: SkinPlayerCorpse");
6096 if ( (m_caster
->GetTypeId() != TYPEID_PLAYER
) || (unitTarget
->GetTypeId() != TYPEID_PLAYER
) || (unitTarget
->isAlive()) )
6099 ((Player
*)unitTarget
)->RemovedInsignia( (Player
*)m_caster
);
6102 void Spell::EffectStealBeneficialBuff(uint32 i
)
6104 sLog
.outDebug("Effect: StealBeneficialBuff");
6106 if(!unitTarget
|| unitTarget
==m_caster
) // can't steal from self
6109 std::vector
<Aura
*> steal_list
;
6110 // Create dispel mask by dispel type
6111 uint32 dispelMask
= GetDispellMask( DispelType(m_spellInfo
->EffectMiscValue
[i
]) );
6112 Unit::AuraMap
const& auras
= unitTarget
->GetAuras();
6113 for(Unit::AuraMap::const_iterator itr
= auras
.begin(); itr
!= auras
.end(); ++itr
)
6115 Aura
*aur
= (*itr
).second
;
6116 if (aur
&& (1<<aur
->GetSpellProto()->Dispel
) & dispelMask
)
6118 // Need check for passive? this
6119 if (aur
->IsPositive() && !aur
->IsPassive())
6120 steal_list
.push_back(aur
);
6123 // Ok if exist some buffs for dispel try dispel it
6124 if (!steal_list
.empty())
6126 std::list
< std::pair
<uint32
,uint64
> > success_list
;
6127 int32 list_size
= steal_list
.size();
6128 // Dispell N = damage buffs (or while exist buffs for dispel)
6129 for (int32 count
=0; count
< damage
&& list_size
> 0; ++count
)
6131 // Random select buff for dispel
6132 Aura
*aur
= steal_list
[urand(0, list_size
-1)];
6133 // Not use chance for steal
6134 // TODO possible need do it
6135 success_list
.push_back( std::pair
<uint32
,uint64
>(aur
->GetId(),aur
->GetCasterGUID()));
6137 // Remove buff from list for prevent doubles
6138 for (std::vector
<Aura
*>::iterator j
= steal_list
.begin(); j
!= steal_list
.end(); )
6141 if (stealed
->GetId() == aur
->GetId() && stealed
->GetCasterGUID() == aur
->GetCasterGUID())
6143 j
= steal_list
.erase(j
);
6150 // Really try steal and send log
6151 if (!success_list
.empty())
6153 int32 count
= success_list
.size();
6154 WorldPacket
data(SMSG_SPELLSTEALLOG
, 8+8+4+1+4+count
*5);
6155 data
.append(unitTarget
->GetPackGUID()); // Victim GUID
6156 data
.append(m_caster
->GetPackGUID()); // Caster GUID
6157 data
<< uint32(m_spellInfo
->Id
); // Dispell spell id
6158 data
<< uint8(0); // not used
6159 data
<< uint32(count
); // count
6160 for (std::list
<std::pair
<uint32
,uint64
> >::iterator j
= success_list
.begin(); j
!= success_list
.end(); ++j
)
6162 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(j
->first
);
6163 data
<< uint32(spellInfo
->Id
); // Spell Id
6164 data
<< uint8(0); // 0 - steals !=0 transfers
6165 unitTarget
->RemoveAurasDueToSpellBySteal(spellInfo
->Id
, j
->second
, m_caster
);
6167 m_caster
->SendMessageToSet(&data
, true);
6172 void Spell::EffectKillCredit(uint32 i
)
6174 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
6177 ((Player
*)unitTarget
)->KilledMonster(m_spellInfo
->EffectMiscValue
[i
], 0);
6180 void Spell::EffectQuestFail(uint32 i
)
6182 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
6185 ((Player
*)unitTarget
)->FailQuest(m_spellInfo
->EffectMiscValue
[i
]);