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"
56 #include "ScriptCalls.h"
58 pEffect SpellEffects
[TOTAL_SPELL_EFFECTS
]=
60 &Spell::EffectNULL
, // 0
61 &Spell::EffectInstaKill
, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG
, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy
, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused
, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits
, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura
, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvirinmentalDMG
, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain
, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech
, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal
, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectUnused
, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL
, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused
, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused
, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused
, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete
, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg
, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect
, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks
, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused
, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused
, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry
, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock
, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem
, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused
, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused
, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA
, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType
, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectMomentMove
, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize
, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg
, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell
, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock
, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem
, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura
, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell
, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused
, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel
, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused
, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield
, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectSummonWild
, // 41 SPELL_EFFECT_SUMMON_WILD
102 &Spell::EffectSummonGuardian
, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
103 &Spell::EffectTeleUnitsFaceCaster
, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill
, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor
, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectNULL
, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
107 &Spell::EffectTradeSkill
, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused
, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused
, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted
, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused
, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused
, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm
, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp
, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature
, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet
, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell
, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg
, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectOpenSecretSafe
, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
120 &Spell::EffectProficiency
, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent
, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn
, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat
, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell
, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectUnused
, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
126 &Spell::EffectUnused
, // 66 SPELL_EFFECT_POWER_FUNNEL unused
127 &Spell::EffectHealMaxHealth
, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast
, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract
, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull
, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket
, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight
, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectSummonGuardian
, // 73 SPELL_EFFECT_SUMMON_POSSESSED
134 &Spell::EffectSummonTotem
, // 74 SPELL_EFFECT_SUMMON_TOTEM
135 &Spell::EffectHealMechanical
, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild
, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect
, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused
, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary
, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints
, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused
, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL
, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel
, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck
, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer
, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject
, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectSummonTotem
, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
148 &Spell::EffectSummonTotem
, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
149 &Spell::EffectSummonTotem
, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
150 &Spell::EffectSummonTotem
, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
151 &Spell::EffectUnused
, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem
, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectUnused
, // 93 SPELL_EFFECT_SUMMON_PHANTASM
154 &Spell::EffectSelfResurrect
, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning
, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge
, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectSummonCritter
, // 97 SPELL_EFFECT_SUMMON_CRITTER
158 &Spell::EffectKnockBack
, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant
, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate
, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet
, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet
, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation
, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject
, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject
, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject
, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject
, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic
, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectSummonDeadPet
, //109 SPELL_EFFECT_SUMMON_DEAD_PET
170 &Spell::EffectDestroyAllTotems
, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage
, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectSummonDemon
, //112 SPELL_EFFECT_SUMMON_DEMON
173 &Spell::EffectResurrectNew
, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt
, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT
, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse
, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal
, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill
, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura
, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused
, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg
, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused
, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi
, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPlayerPull
, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
185 &Spell::EffectModifyThreatPercent
, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff
, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting
, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura
, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura
, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectNULL
, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectUnused
, //131 SPELL_EFFECT_131 used in some test spells
192 &Spell::EffectNULL
, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
193 &Spell::EffectUnlearnSpecialization
, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit
, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL
, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct
, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergisePct
, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectNULL
, //138 SPELL_EFFECT_138 Leap
199 &Spell::EffectUnused
, //139 SPELL_EFFECT_139 unused
200 &Spell::EffectForceCast
, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectNULL
, //141 SPELL_EFFECT_141 damage and reduce speed?
202 &Spell::EffectTriggerSpellWithValue
, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura
, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectNULL
, //144 SPELL_EFFECT_144 Spectral Blast
205 &Spell::EffectNULL
, //145 SPELL_EFFECT_145 Black Hole Effect
206 &Spell::EffectUnused
, //146 SPELL_EFFECT_146 unused
207 &Spell::EffectQuestFail
, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectUnused
, //148 SPELL_EFFECT_148 unused
209 &Spell::EffectNULL
, //149 SPELL_EFFECT_149 swoop
210 &Spell::EffectUnused
, //150 SPELL_EFFECT_150 unused
211 &Spell::EffectTriggerRitualOfSummoning
, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectNULL
, //152 SPELL_EFFECT_152 summon Refer-a-Friend
213 &Spell::EffectNULL
, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
216 void Spell::EffectNULL(uint32
/*i*/)
218 sLog
.outDebug("WORLD: Spell Effect DUMMY");
221 void Spell::EffectUnused(uint32
/*i*/)
223 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
226 void Spell::EffectResurrectNew(uint32 i
)
228 if(!unitTarget
|| unitTarget
->isAlive())
231 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
234 if(!unitTarget
->IsInWorld())
237 Player
* pTarget
= ((Player
*)unitTarget
);
239 if(pTarget
->isRessurectRequested()) // already have one active request
242 uint32 health
= damage
;
243 uint32 mana
= m_spellInfo
->EffectMiscValue
[i
];
244 pTarget
->setResurrectRequestData(m_caster
->GetGUID(), m_caster
->GetMapId(), m_caster
->GetPositionX(), m_caster
->GetPositionY(), m_caster
->GetPositionZ(), health
, mana
);
245 SendResurrectRequest(pTarget
);
248 void Spell::EffectInstaKill(uint32
/*i*/)
250 if( !unitTarget
|| !unitTarget
->isAlive() )
254 if(m_spellInfo
->Id
==18788 && unitTarget
->GetTypeId()==TYPEID_UNIT
)
256 uint32 entry
= unitTarget
->GetEntry();
260 case 416: spellID
=18789; break; //imp
261 case 417: spellID
=18792; break; //fellhunter
262 case 1860: spellID
=18790; break; //void
263 case 1863: spellID
=18791; break; //succubus
264 case 17252: spellID
=35701; break; //fellguard
266 sLog
.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry
);
270 m_caster
->CastSpell(m_caster
,spellID
,true);
273 if(m_caster
==unitTarget
) // prevent interrupt message
276 uint32 health
= unitTarget
->GetHealth();
277 m_caster
->DealDamage(unitTarget
, health
, NULL
, DIRECT_DAMAGE
, SPELL_SCHOOL_MASK_NORMAL
, NULL
, false);
280 void Spell::EffectEnvirinmentalDMG(uint32 i
)
285 // Note: this hack with damage replace required until GO casting not implemented
286 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
287 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
288 damage
= m_spellInfo
->EffectBasePoints
[i
]+m_spellInfo
->EffectBaseDice
[i
];
290 m_caster
->CalcAbsorbResist(m_caster
,GetSpellSchoolMask(m_spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
292 m_caster
->SendSpellNonMeleeDamageLog(m_caster
, m_spellInfo
->Id
, damage
, GetSpellSchoolMask(m_spellInfo
), absorb
, resist
, false, 0, false);
293 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
294 ((Player
*)m_caster
)->EnvironmentalDamage(m_caster
->GetGUID(),DAMAGE_FIRE
,damage
);
297 void Spell::EffectSchoolDMG(uint32 effect_idx
)
299 if( unitTarget
&& unitTarget
->isAlive())
301 switch(m_spellInfo
->SpellFamilyName
)
303 case SPELLFAMILY_GENERIC
:
306 if(m_spellInfo
->SpellIconID
== 2269 )
308 damage
+= rand()%2 ? damage
: 0;
311 switch(m_spellInfo
->Id
) // better way to check unknown
313 // Meteor like spells (divided damage to targets)
314 case 24340: case 26558: case 28884: // Meteor
315 case 36837: case 38903: case 41276: // Meteor
316 case 26789: // Shard of the Fallen Star
317 case 31436: // Malevolent Cleave
318 case 35181: // Dive Bomb
319 case 40810: case 43267: case 43268: // Saber Lash
320 case 42384: // Brutal Swipe
321 case 45150: // Meteor Slash
324 for(std::list
<TargetInfo
>::iterator ihit
= m_UniqueTargetInfo
.begin();ihit
!= m_UniqueTargetInfo
.end();++ihit
)
325 if(ihit
->effectMask
& (1<<effect_idx
))
328 damage
/= count
; // divide to all targets
331 // percent from health with min
332 case 25599: // Thundercrash
334 damage
= unitTarget
->GetHealth() / 2;
343 case SPELLFAMILY_MAGE
:
346 if(m_spellInfo
->SpellFamilyFlags
& 0x20000000LL
)
348 m_caster
->CastSpell(m_caster
,36032,true);
352 case SPELLFAMILY_WARRIOR
:
355 if(m_spellInfo
->SpellFamilyFlags
& 0x40000000000LL
)
357 damage
= uint32(damage
* (m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)) / 100);
360 else if(m_spellInfo
->SpellFamilyFlags
& 0x100000000LL
)
361 damage
+= int32(m_caster
->GetShieldBlockValue());
363 else if(m_spellInfo
->SpellFamilyFlags
& 0x10000000000LL
)
365 damage
= uint32(damage
* m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
) / 100);
366 m_caster
->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH
, false);
370 case SPELLFAMILY_WARLOCK
:
372 // Incinerate Rank 1 & 2
373 if((m_spellInfo
->SpellFamilyFlags
& 0x00004000000000LL
) && m_spellInfo
->SpellIconID
==2128)
375 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
376 if(unitTarget
->HasAuraState(AURA_STATE_IMMOLATE
))
377 damage
+= int32(damage
*0.25);
381 case SPELLFAMILY_DRUID
:
384 if((m_spellInfo
->SpellFamilyFlags
& 0x000800000) && m_spellInfo
->SpellVisual
==6587)
386 // converts each extra point of energy into ($f1+$AP/630) additional damage
387 float multiple
= m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
) / 630 + m_spellInfo
->DmgMultiplier
[effect_idx
];
388 damage
+= int32(m_caster
->GetPower(POWER_ENERGY
) * multiple
);
389 m_caster
->SetPower(POWER_ENERGY
,0);
392 else if(m_spellInfo
->SpellFamilyFlags
& 0x0000000000001000LL
)
394 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
) / 100);
397 else if(m_spellInfo
->SpellFamilyFlags
& 0x0010000000000000LL
)
399 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)*0.08f
);
402 else if ( m_spellInfo
->SpellFamilyFlags
& 0x0004LL
)
404 Unit::AuraList
const& m_OverrideClassScript
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
405 for(Unit::AuraList::const_iterator i
= m_OverrideClassScript
.begin(); i
!= m_OverrideClassScript
.end(); ++i
)
407 // Starfire Bonus (caster)
408 switch((*i
)->GetModifier()->m_miscvalue
)
410 case 5481: // Nordrassil Regalia - bonus
412 Unit::AuraList
const& m_periodicDamageAuras
= unitTarget
->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE
);
413 for(Unit::AuraList::const_iterator itr
= m_periodicDamageAuras
.begin(); itr
!= m_periodicDamageAuras
.end(); ++itr
)
415 // Moonfire or Insect Swarm (target debuff from any casters)
416 if ( (*itr
)->GetSpellProto()->SpellFamilyFlags
& 0x00200002LL
)
418 int32 mod
= (*i
)->GetModifier()->m_amount
;
419 damage
+= damage
*mod
/100;
425 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
427 damage
+= (*i
)->GetModifier()->m_amount
;
433 //Mangle Bonus for the initial damage of Lacerate and Rake
434 if((m_spellInfo
->SpellFamilyFlags
==0x0000000000001000LL
&& m_spellInfo
->SpellIconID
==494) ||
435 (m_spellInfo
->SpellFamilyFlags
==0x0000010000000000LL
&& m_spellInfo
->SpellIconID
==2246))
437 Unit::AuraList
const& mDummyAuras
= unitTarget
->GetAurasByType(SPELL_AURA_DUMMY
);
438 for(Unit::AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
439 if((*i
)->GetSpellProto()->SpellFamilyFlags
& 0x0000044000000000LL
&& (*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_DRUID
)
441 damage
= int32(damage
*(100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
);
447 case SPELLFAMILY_ROGUE
:
450 if(m_caster
->GetTypeId()==TYPEID_PLAYER
&& (m_spellInfo
->SpellFamilyFlags
& 0x800000000LL
))
452 // consume from stack dozes not more that have combo-points
453 if(uint32 combo
= ((Player
*)m_caster
)->GetComboPoints())
455 // count consumed deadly poison doses at target
458 // remove consumed poison doses
459 Unit::AuraList
const& auras
= unitTarget
->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE
);
460 for(Unit::AuraList::const_iterator itr
= auras
.begin(); itr
!=auras
.end() && combo
;)
462 // Deadly poison (only attacker applied)
463 if( (*itr
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& ((*itr
)->GetSpellProto()->SpellFamilyFlags
& 0x10000) &&
464 (*itr
)->GetSpellProto()->SpellVisual
==5100 && (*itr
)->GetCasterGUID()==m_caster
->GetGUID() )
469 unitTarget
->RemoveSingleAuraFromStack((*itr
)->GetId(), (*itr
)->GetEffIndex());
478 damage
+= int32(((Player
*)m_caster
)->GetTotalAttackPowerValue(BASE_ATTACK
) * 0.03f
* doses
);
480 // Eviscerate and Envenom Bonus Damage (item set effect)
481 if(m_caster
->GetDummyAura(37169))
482 damage
+= ((Player
*)m_caster
)->GetComboPoints()*40;
486 else if((m_spellInfo
->SpellFamilyFlags
& 0x00020000LL
) && m_caster
->GetTypeId()==TYPEID_PLAYER
)
488 if(uint32 combo
= ((Player
*)m_caster
)->GetComboPoints())
490 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
) * combo
* 0.03f
);
492 // Eviscerate and Envenom Bonus Damage (item set effect)
493 if(m_caster
->GetDummyAura(37169))
499 case SPELLFAMILY_HUNTER
:
502 if((m_spellInfo
->SpellFamilyFlags
& 0x000000002) && m_spellInfo
->SpellVisual
==342)
504 damage
+= int32(m_caster
->GetTotalAttackPowerValue(BASE_ATTACK
)*0.2);
507 else if((m_spellInfo
->SpellFamilyFlags
& 0x00000800) && m_spellInfo
->maxLevel
> 0)
509 damage
+= int32(m_caster
->GetTotalAttackPowerValue(RANGED_ATTACK
)*0.15);
512 else if(m_spellInfo
->SpellFamilyFlags
& 0x100000000LL
)
514 int32 base
= irand((int32
)m_caster
->GetWeaponDamageRange(RANGED_ATTACK
, MINDAMAGE
),(int32
)m_caster
->GetWeaponDamageRange(RANGED_ATTACK
, MAXDAMAGE
));
515 damage
+= int32(float(base
)/m_caster
->GetAttackTime(RANGED_ATTACK
)*2800 + m_caster
->GetTotalAttackPowerValue(RANGED_ATTACK
)*0.2f
);
517 //Explosive Trap Effect
518 else if(m_spellInfo
->SpellFamilyFlags
& 0x00000004)
520 damage
+= int32(m_caster
->GetTotalAttackPowerValue(RANGED_ATTACK
)*0.1);
524 case SPELLFAMILY_PALADIN
:
526 //Judgement of Vengeance
527 if((m_spellInfo
->SpellFamilyFlags
& 0x800000000LL
) && m_spellInfo
->SpellIconID
==2292)
530 Unit::AuraList
const& auras
= unitTarget
->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE
);
531 for(Unit::AuraList::const_iterator itr
= auras
.begin(); itr
!=auras
.end(); ++itr
)
532 if((*itr
)->GetId() == 31803 && (*itr
)->GetCasterGUID()==m_caster
->GetGUID())
535 //No damage if the target isn't affected by this
549 void Spell::EffectDummy(uint32 i
)
551 if(!unitTarget
&& !gameObjTarget
&& !itemTarget
)
554 // selection by spell family
555 switch(m_spellInfo
->SpellFamilyName
)
557 case SPELLFAMILY_GENERIC
:
559 switch(m_spellInfo
->Id
)
561 case 8063: // Deviate Fish
563 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
569 case 1: spell_id
= 8064; break; // Sleepy
570 case 2: spell_id
= 8065; break; // Invigorate
571 case 3: spell_id
= 8066; break; // Shrink
572 case 4: spell_id
= 8067; break; // Party Time!
573 case 5: spell_id
= 8068; break; // Healthy Spirit
575 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
578 case 8213: // Savory Deviate Delight
580 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
587 case 1: spell_id
= (m_caster
->getGender() == GENDER_MALE
? 8219 : 8220); break;
589 case 2: spell_id
= (m_caster
->getGender() == GENDER_MALE
? 8221 : 8222); break;
591 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
594 case 8593: // Symbol of life (restore creature to life)
595 case 31225: // Shimmering Vessel (restore creature to life)
597 if(!unitTarget
|| unitTarget
->GetTypeId()!=TYPEID_UNIT
)
599 ((Creature
*)unitTarget
)->setDeathState(JUST_ALIVED
);
602 case 12162: // Deep wounds
603 case 12850: // (now good common check for this spells)
610 // DW should benefit of attack power, damage percent mods etc.
611 // TODO: check if using offhand damage is correct and if it should be divided by 2
612 if (m_caster
->haveOffhandWeapon() && m_caster
->getAttackTimer(BASE_ATTACK
) > m_caster
->getAttackTimer(OFF_ATTACK
))
613 damage
= (m_caster
->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
) + m_caster
->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
))/2;
615 damage
= (m_caster
->GetFloatValue(UNIT_FIELD_MINDAMAGE
) + m_caster
->GetFloatValue(UNIT_FIELD_MAXDAMAGE
))/2;
617 switch (m_spellInfo
->Id
)
619 case 12850: damage
*= 0.2f
; break;
620 case 12162: damage
*= 0.4f
; break;
621 case 12868: damage
*= 0.6f
; break;
623 sLog
.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo
->Id
);
627 int32 deepWoundsDotBasePoints0
= int32(damage
/ 4);
628 m_caster
->CastCustomSpell(unitTarget
, 12721, &deepWoundsDotBasePoints0
, NULL
, NULL
, true, NULL
);
631 case 12975: //Last Stand
633 int32 healthModSpellBasePoints0
= int32(m_caster
->GetMaxHealth()*0.3);
634 m_caster
->CastCustomSpell(m_caster
, 12976, &healthModSpellBasePoints0
, NULL
, NULL
, true, NULL
);
637 case 13120: // net-o-matic
644 uint32 roll
= urand(0, 99);
646 if(roll
< 2) // 2% for 30 sec self root (off-like chance unknown)
648 else if(roll
< 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
653 m_caster
->CastSpell(unitTarget
,spell_id
,true,NULL
);
656 case 13567: // Dummy Trigger
658 // can be used for different aura triggering, so select by aura
659 if(!m_triggeredByAuraSpell
|| !unitTarget
)
662 switch(m_triggeredByAuraSpell
->Id
)
664 case 26467: // Persistent Shield
665 m_caster
->CastCustomSpell(unitTarget
, 26470, &damage
, NULL
, NULL
, true);
668 sLog
.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell
->Id
);
673 case 14185: // Preparation Rogue
675 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
678 //immediately finishes the cooldown on certain Rogue abilities
679 const PlayerSpellMap
& sp_list
= ((Player
*)m_caster
)->GetSpellMap();
680 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
682 uint32 classspell
= itr
->first
;
683 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(classspell
);
685 if (spellInfo
->SpellFamilyName
== SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& 0x26000000860LL
))
687 ((Player
*)m_caster
)->RemoveSpellCooldown(classspell
);
689 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
690 data
<< uint32(classspell
);
691 data
<< uint64(m_caster
->GetGUID());
692 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
697 case 15998: // Capture Worg Pup
698 case 29435: // Capture Female Kaliri Hatchling
700 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
)
703 Creature
* creatureTarget
= (Creature
*)unitTarget
;
704 creatureTarget
->setDeathState(JUST_DIED
);
705 creatureTarget
->RemoveCorpse();
706 creatureTarget
->SetHealth(0); // just for nice GM-mode view
709 case 16589: // Noggenfogger Elixir
711 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
717 case 1: spell_id
= 16595; break;
718 case 2: spell_id
= 16593; break;
719 default:spell_id
= 16591; break;
722 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
725 case 17251: // Spirit Healer Res
727 if(!unitTarget
|| !m_originalCaster
)
730 if(m_originalCaster
->GetTypeId() == TYPEID_PLAYER
)
732 WorldPacket
data(SMSG_SPIRIT_HEALER_CONFIRM
, 8);
733 data
<< unitTarget
->GetGUID();
734 ((Player
*)m_originalCaster
)->GetSession()->SendPacket( &data
);
738 case 17271: // Test Fetid Skull
740 if(!itemTarget
&& m_caster
->GetTypeId()!=TYPEID_PLAYER
)
743 uint32 spell_id
= roll_chance_i(50) ? 17269 : 17270;
745 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
748 case 20577: // Cannibalize
750 m_caster
->CastSpell(m_caster
,20578,false,NULL
);
752 case 23019: // Crystal Prison Dummy DND
754 if(!unitTarget
|| !unitTarget
->isAlive() || unitTarget
->GetTypeId() != TYPEID_UNIT
|| ((Creature
*)unitTarget
)->isPet())
757 Creature
* creatureTarget
= (Creature
*)unitTarget
;
758 if(creatureTarget
->isPet())
761 creatureTarget
->setDeathState(JUST_DIED
);
762 creatureTarget
->RemoveCorpse();
763 creatureTarget
->SetHealth(0); // just for nice GM-mode view
765 GameObject
* pGameObj
= new GameObject
;
767 Map
*map
= creatureTarget
->GetMap();
769 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), 179644, map
,
770 creatureTarget
->GetPositionX(), creatureTarget
->GetPositionY(), creatureTarget
->GetPositionZ(),
771 creatureTarget
->GetOrientation(), 0, 0, 0, 0, 100, 1) )
777 pGameObj
->SetRespawnTime(creatureTarget
->GetRespawnTime()-time(NULL
));
778 pGameObj
->SetOwnerGUID(m_caster
->GetGUID() );
779 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel() );
780 pGameObj
->SetSpellId(m_spellInfo
->Id
);
782 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
785 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
786 data
<< uint64(pGameObj
->GetGUID());
787 m_caster
->SendMessageToSet(&data
,true);
791 case 23074: // Arc. Dragonling
792 if (!m_CastItem
) return;
793 m_caster
->CastSpell(m_caster
,19804,true,m_CastItem
);
795 case 23075: // Mithril Mechanical Dragonling
796 if (!m_CastItem
) return;
797 m_caster
->CastSpell(m_caster
,12749,true,m_CastItem
);
799 case 23076: // Mechanical Dragonling
800 if (!m_CastItem
) return;
801 m_caster
->CastSpell(m_caster
,4073,true,m_CastItem
);
803 case 23133: // Gnomish Battle Chicken
804 if (!m_CastItem
) return;
805 m_caster
->CastSpell(m_caster
,13166,true,m_CastItem
);
807 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
809 int32 r
= irand(0, 119);
810 if ( r
< 20 ) // 1/6 polymorph
811 m_caster
->CastSpell(m_caster
,23444,true);
812 else if ( r
< 100 ) // 4/6 evil twin
813 m_caster
->CastSpell(m_caster
,23445,true);
814 else // 1/6 miss the target
815 m_caster
->CastSpell(m_caster
,36902,true);
818 case 23453: // Ultrasafe Transporter: Gadgetzan
819 if ( roll_chance_i(50) ) // success
820 m_caster
->CastSpell(m_caster
,23441,true);
822 m_caster
->CastSpell(m_caster
,23446,true);
824 case 23645: // Hourglass Sand
825 m_caster
->RemoveAurasDueToSpell(23170);
827 case 23725: // Gift of Life (warrior bwl trinket)
828 m_caster
->CastSpell(m_caster
,23782,true);
829 m_caster
->CastSpell(m_caster
,23783,true);
831 case 25860: // Reindeer Transformation
833 if (!m_caster
->HasAuraType(SPELL_AURA_MOUNTED
))
836 float flyspeed
= m_caster
->GetSpeedRate(MOVE_FLIGHT
);
837 float speed
= m_caster
->GetSpeedRate(MOVE_RUN
);
839 m_caster
->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED
);
841 //5 different spells used depending on mounted speed and if mount can fly or not
842 if (flyspeed
>= 4.1f
)
843 m_caster
->CastSpell(m_caster
, 44827, true); //310% flying Reindeer
844 else if (flyspeed
>= 3.8f
)
845 m_caster
->CastSpell(m_caster
, 44825, true); //280% flying Reindeer
846 else if (flyspeed
>= 1.6f
)
847 m_caster
->CastSpell(m_caster
, 44824, true); //60% flying Reindeer
848 else if (speed
>= 2.0f
)
849 m_caster
->CastSpell(m_caster
, 25859, true); //100% ground Reindeer
851 m_caster
->CastSpell(m_caster
, 25858, true); //60% ground Reindeer
855 //case 26074: // Holiday Cheer
856 // return; -- implemented at client side
857 case 28006: // Arcane Cloaking
859 if( unitTarget
->GetTypeId() == TYPEID_PLAYER
)
860 m_caster
->CastSpell(unitTarget
,29294,true);
863 case 28730: // Arcane Torrent (Mana)
866 Unit::AuraList
const& m_dummyAuras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
867 for(Unit::AuraList::const_iterator i
= m_dummyAuras
.begin(); i
!= m_dummyAuras
.end(); ++i
)
868 if ((*i
)->GetId() == 28734)
872 m_caster
->RemoveAurasDueToSpell(28734);
873 int32 bp
= damage
* count
;
874 m_caster
->CastCustomSpell(m_caster
, 28733, &bp
, NULL
, NULL
, true);
878 case 29200: // Purify Helboar Meat
880 if( m_caster
->GetTypeId() != TYPEID_PLAYER
)
883 uint32 spell_id
= roll_chance_i(50) ? 29277 : 29278;
885 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
888 case 29858: // Soulshatter
889 if (unitTarget
&& unitTarget
->GetTypeId() == TYPEID_UNIT
&& unitTarget
->IsHostileTo(m_caster
))
890 m_caster
->CastSpell(unitTarget
,32835,true);
892 case 30458: // Nigh Invulnerability
893 if (!m_CastItem
) return;
894 if(roll_chance_i(86)) // success
895 m_caster
->CastSpell(m_caster
, 30456, true, m_CastItem
);
896 else // backfire in 14% casts
897 m_caster
->CastSpell(m_caster
, 30457, true, m_CastItem
);
899 case 30507: // Poultryizer
900 if (!m_CastItem
) return;
901 if(roll_chance_i(80)) // success
902 m_caster
->CastSpell(unitTarget
, 30501, true, m_CastItem
);
904 m_caster
->CastSpell(unitTarget
, 30504, true, m_CastItem
);
906 case 33060: // Make a Wish
908 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
915 case 1: spell_id
= 33053; break;
916 case 2: spell_id
= 33057; break;
917 case 3: spell_id
= 33059; break;
918 case 4: spell_id
= 33062; break;
919 case 5: spell_id
= 33064; break;
922 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
928 switch(m_caster
->GetAreaId())
930 case 3900: spell_id
= 35743; break;
931 case 3742: spell_id
= 35744; break;
935 m_caster
->CastSpell(m_caster
,spell_id
,true);
938 case 37674: // Chaos Blast
943 int32 basepoints0
= 100;
944 m_caster
->CastCustomSpell(unitTarget
,37675,&basepoints0
,NULL
,NULL
,true);
947 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
949 // selecting one from Bloodstained Fortune item
953 case 1: newitemid
= 32688; break;
954 case 2: newitemid
= 32689; break;
955 case 3: newitemid
= 32690; break;
956 case 4: newitemid
= 32691; break;
957 case 5: newitemid
= 32692; break;
958 case 6: newitemid
= 32693; break;
959 case 7: newitemid
= 32700; break;
960 case 8: newitemid
= 32701; break;
961 case 9: newitemid
= 32702; break;
962 case 10: newitemid
= 32703; break;
963 case 11: newitemid
= 32704; break;
964 case 12: newitemid
= 32705; break;
965 case 13: newitemid
= 32706; break;
966 case 14: newitemid
= 32707; break;
967 case 15: newitemid
= 32708; break;
968 case 16: newitemid
= 32709; break;
969 case 17: newitemid
= 32710; break;
970 case 18: newitemid
= 32711; break;
971 case 19: newitemid
= 32712; break;
972 case 20: newitemid
= 32713; break;
977 DoCreateItem(i
,newitemid
);
980 // Demon Broiled Surprise
981 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
984 if (m_caster->GetTypeId() != TYPEID_PLAYER)
987 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
991 case 44875: // Complete Raptor Capture
993 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
)
996 Creature
* creatureTarget
= (Creature
*)unitTarget
;
998 creatureTarget
->setDeathState(JUST_DIED
);
999 creatureTarget
->RemoveCorpse();
1000 creatureTarget
->SetHealth(0); // just for nice GM-mode view
1002 //cast spell Raptor Capture Credit
1003 m_caster
->CastSpell(m_caster
,42337,true,NULL
);
1006 case 37573: //Temporal Phase Modulator
1011 TemporarySummon
* tempSummon
= dynamic_cast<TemporarySummon
*>(unitTarget
);
1015 uint32 health
= tempSummon
->GetHealth();
1016 const uint32 entry_list
[6] = {21821, 21820, 21817};
1018 float x
= tempSummon
->GetPositionX();
1019 float y
= tempSummon
->GetPositionY();
1020 float z
= tempSummon
->GetPositionZ();
1021 float o
= tempSummon
->GetOrientation();
1023 tempSummon
->UnSummon();
1025 Creature
* pCreature
= m_caster
->SummonCreature(entry_list
[urand(0, 2)], x
, y
, z
, o
,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
,180000);
1029 pCreature
->SetHealth(health
);
1032 pCreature
->AI()->AttackStart(m_caster
);
1036 case 34665: //Administer Antidote
1038 if(!unitTarget
|| m_caster
->GetTypeId() != TYPEID_PLAYER
)
1044 TemporarySummon
* tempSummon
= dynamic_cast<TemporarySummon
*>(unitTarget
);
1048 uint32 health
= tempSummon
->GetHealth();
1050 float x
= tempSummon
->GetPositionX();
1051 float y
= tempSummon
->GetPositionY();
1052 float z
= tempSummon
->GetPositionZ();
1053 float o
= tempSummon
->GetOrientation();
1054 tempSummon
->UnSummon();
1056 Creature
* pCreature
= m_caster
->SummonCreature(16992, x
, y
, z
, o
,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
,180000);
1060 pCreature
->SetHealth(health
);
1061 ((Player
*)m_caster
)->KilledMonster(16992,pCreature
->GetGUID());
1063 if (pCreature
->AI())
1064 pCreature
->AI()->AttackStart(m_caster
);
1068 case 44997: // Converting Sentry
1070 //Converted Sentry Credit
1071 m_caster
->CastSpell(m_caster
, 45009, true);
1074 case 45030: // Impale Emissary
1076 // Emissary of Hate Credit
1077 m_caster
->CastSpell(m_caster
, 45088, true);
1080 case 50243: // Teach Language
1082 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1085 // spell has a 1/3 chance to trigger one of the below
1086 if(roll_chance_i(66))
1088 if(((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
1090 // 1000001 - gnomish binary
1091 m_caster
->CastSpell(m_caster
, 50242, true);
1095 // 01001000 - goblin binary
1096 m_caster
->CastSpell(m_caster
, 50246, true);
1101 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1103 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1106 if(BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround())
1107 bg
->EventPlayerDroppedFlag((Player
*)m_caster
);
1109 m_caster
->CastSpell(m_caster
, 30452, true, NULL
);
1114 //All IconID Check in there
1115 switch(m_spellInfo
->SpellIconID
)
1117 // Berserking (troll racial traits)
1120 uint32 healthPerc
= uint32((float(m_caster
->GetHealth())/m_caster
->GetMaxHealth())*100);
1121 int32 melee_mod
= 10;
1122 if (healthPerc
<= 40)
1124 if (healthPerc
< 100 && healthPerc
> 40)
1125 melee_mod
= 10+(100-healthPerc
)/3;
1127 int32 hasteModBasePoints0
= melee_mod
; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1128 int32 hasteModBasePoints1
= (5-melee_mod
);
1129 int32 hasteModBasePoints2
= 5;
1131 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1132 m_caster
->ModifyAuraState(AURA_STATE_BERSERKING
,true);
1133 m_caster
->CastCustomSpell(m_caster
,26635,&hasteModBasePoints0
,&hasteModBasePoints1
,&hasteModBasePoints2
,true,NULL
);
1139 case SPELLFAMILY_MAGE
:
1140 switch(m_spellInfo
->Id
)
1142 case 11958: // Cold Snap
1144 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
1147 // immediately finishes the cooldown on Frost spells
1148 const PlayerSpellMap
& sp_list
= ((Player
*)m_caster
)->GetSpellMap();
1149 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
1151 if (itr
->second
->state
== PLAYERSPELL_REMOVED
)
1154 uint32 classspell
= itr
->first
;
1155 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(classspell
);
1157 if( spellInfo
->SpellFamilyName
== SPELLFAMILY_MAGE
&&
1158 (GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_FROST
) &&
1159 spellInfo
->Id
!= 11958 && GetSpellRecoveryTime(spellInfo
) > 0 )
1161 ((Player
*)m_caster
)->RemoveSpellCooldown(classspell
);
1163 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
1164 data
<< uint32(classspell
);
1165 data
<< uint64(m_caster
->GetGUID());
1166 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
1173 if ( unitTarget
&& unitTarget
->GetTypeId() == TYPEID_UNIT
)
1175 //Polymorph Cast Visual Rank 1
1176 const uint32 spell_list
[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1177 unitTarget
->CastSpell( unitTarget
, spell_list
[urand(0, 5)], true);
1183 case SPELLFAMILY_WARRIOR
:
1185 if(m_spellInfo
->SpellFamilyFlags
& 0x1 && m_spellInfo
->SpellVisual
== 867)
1187 int32 chargeBasePoints0
= damage
;
1188 m_caster
->CastCustomSpell(m_caster
,34846,&chargeBasePoints0
,NULL
,NULL
,true);
1192 if(m_spellInfo
->SpellFamilyFlags
& 0x20000000)
1197 int32 basePoints0
= damage
+int32(m_caster
->GetPower(POWER_RAGE
) * m_spellInfo
->DmgMultiplier
[i
]);
1198 m_caster
->CastCustomSpell(unitTarget
, 20647, &basePoints0
, NULL
, NULL
, true, 0);
1199 m_caster
->SetPower(POWER_RAGE
,0);
1202 if(m_spellInfo
->Id
==21977) //Warrior's Wrath
1207 m_caster
->CastSpell(unitTarget
,21887,true); // spell mod
1211 case SPELLFAMILY_WARLOCK
:
1212 //Life Tap (only it have this with dummy effect)
1213 if (m_spellInfo
->SpellFamilyFlags
== 0x40000)
1215 float cost
= m_currentBasePoints
[0]+1;
1217 if(Player
* modOwner
= m_caster
->GetSpellModOwner())
1218 modOwner
->ApplySpellMod(m_spellInfo
->Id
, SPELLMOD_COST
, cost
,this);
1220 int32 dmg
= m_caster
->SpellDamageBonus(m_caster
, m_spellInfo
,uint32(cost
> 0 ? cost
: 0), SPELL_DIRECT_DAMAGE
);
1222 if(int32(m_caster
->GetHealth()) > dmg
)
1224 // Shouldn't Appear in Combat Log
1225 m_caster
->ModifyHealth(-dmg
);
1229 Unit::AuraList
const& auraDummy
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
1230 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!= auraDummy
.end(); ++itr
)
1232 // only Imp. Life Tap have this in combination with dummy aura
1233 if((*itr
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_WARLOCK
&& (*itr
)->GetSpellProto()->SpellIconID
== 208)
1234 mana
= ((*itr
)->GetModifier()->m_amount
+ 100)* mana
/ 100;
1237 m_caster
->CastCustomSpell(m_caster
,31818,&mana
,NULL
,NULL
,true,NULL
);
1240 int32 manaFeedVal
= m_caster
->CalculateSpellDamage(m_spellInfo
,1, m_spellInfo
->EffectBasePoints
[1],m_caster
);
1241 manaFeedVal
= manaFeedVal
* mana
/ 100;
1243 m_caster
->CastCustomSpell(m_caster
,32553,&manaFeedVal
,NULL
,NULL
,true,NULL
);
1246 SendCastResult(SPELL_FAILED_FIZZLE
);
1250 case SPELLFAMILY_PRIEST
:
1251 switch(m_spellInfo
->Id
)
1253 case 28598: // Touch of Weakness triggered spell
1255 if(!unitTarget
|| !m_triggeredByAuraSpell
)
1259 switch(m_triggeredByAuraSpell
->Id
)
1261 case 2652: spellid
= 2943; break; // Rank 1
1262 case 19261: spellid
= 19249; break; // Rank 2
1263 case 19262: spellid
= 19251; break; // Rank 3
1264 case 19264: spellid
= 19252; break; // Rank 4
1265 case 19265: spellid
= 19253; break; // Rank 5
1266 case 19266: spellid
= 19254; break; // Rank 6
1267 case 25461: spellid
= 25460; break; // Rank 7
1269 sLog
.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell
->Id
);
1272 m_caster
->CastSpell(unitTarget
, spellid
, true, NULL
);
1277 case SPELLFAMILY_DRUID
:
1278 switch(m_spellInfo
->Id
)
1280 case 5420: // Tree of Life passive
1282 // Tree of Life area effect
1283 int32 health_mod
= int32(m_caster
->GetStat(STAT_SPIRIT
)/4);
1284 m_caster
->CastCustomSpell(m_caster
,34123,&health_mod
,NULL
,NULL
,true,NULL
);
1289 case SPELLFAMILY_ROGUE
:
1290 switch(m_spellInfo
->Id
)
1292 case 31231: // Cheat Death
1294 m_caster
->CastSpell(m_caster
,45182,true);
1299 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1302 Player
*pCaster
= ((Player
*)m_caster
);
1304 Item
*item
= pCaster
->GetWeaponForAttack(OFF_ATTACK
);
1308 // all poison enchantments is temporary
1309 uint32 enchant_id
= item
->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT
);
1313 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
1317 for (int s
=0;s
<3;s
++)
1319 if(pEnchant
->type
[s
]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
)
1322 SpellEntry
const* combatEntry
= sSpellStore
.LookupEntry(pEnchant
->spellid
[s
]);
1323 if(!combatEntry
|| combatEntry
->Dispel
!= DISPEL_POISON
)
1326 m_caster
->CastSpell(unitTarget
, combatEntry
, true, item
);
1329 m_caster
->CastSpell(unitTarget
, 5940, true);
1334 case SPELLFAMILY_HUNTER
:
1336 if(m_spellInfo
->SpellFamilyFlags
& 0x100000000LL
)
1338 if( !unitTarget
|| !unitTarget
->isAlive())
1343 // check dazed affect
1344 Unit::AuraList
const& decSpeedList
= unitTarget
->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED
);
1345 for(Unit::AuraList::const_iterator iter
= decSpeedList
.begin(); iter
!= decSpeedList
.end(); ++iter
)
1347 if((*iter
)->GetSpellProto()->SpellIconID
==15 && (*iter
)->GetSpellProto()->Dispel
==0)
1359 if(m_spellInfo
->SpellFamilyFlags
& 0x00080000000000LL
)
1361 if(m_caster
->getClass()!=CLASS_HUNTER
)
1364 // clear hunter crit aura state
1365 m_caster
->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
,false);
1367 // additional damage from pet to pet target
1368 Pet
* pet
= m_caster
->GetPet();
1369 if(!pet
|| !pet
->getVictim())
1372 uint32 spell_id
= 0;
1373 switch (m_spellInfo
->Id
)
1375 case 34026: spell_id
= 34027; break; // rank 1
1377 sLog
.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo
->Id
);
1381 pet
->CastSpell(pet
->getVictim(), spell_id
, true);
1385 switch(m_spellInfo
->Id
)
1387 case 23989: //Readiness talent
1389 if(m_caster
->GetTypeId()!=TYPEID_PLAYER
)
1392 //immediately finishes the cooldown for hunter abilities
1393 const PlayerSpellMap
& sp_list
= ((Player
*)m_caster
)->GetSpellMap();
1394 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
1396 uint32 classspell
= itr
->first
;
1397 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(classspell
);
1399 if (spellInfo
->SpellFamilyName
== SPELLFAMILY_HUNTER
&& spellInfo
->Id
!= 23989 && GetSpellRecoveryTime(spellInfo
) > 0 )
1401 ((Player
*)m_caster
)->RemoveSpellCooldown(classspell
);
1403 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
1404 data
<< uint32(classspell
);
1405 data
<< uint64(m_caster
->GetGUID());
1406 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
1411 case 37506: // Scatter Shot
1413 if (m_caster
->GetTypeId()!=TYPEID_PLAYER
)
1416 // break Auto Shot and autohit
1417 m_caster
->InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
1418 m_caster
->AttackStop();
1419 ((Player
*)m_caster
)->SendAttackSwingCancelAttack();
1424 case SPELLFAMILY_PALADIN
:
1425 switch(m_spellInfo
->SpellIconID
)
1427 case 156: // Holy Shock
1435 switch(m_spellInfo
->Id
)
1437 case 20473: hurt
= 25912; heal
= 25914; break;
1438 case 20929: hurt
= 25911; heal
= 25913; break;
1439 case 20930: hurt
= 25902; heal
= 25903; break;
1440 case 27174: hurt
= 27176; heal
= 27175; break;
1441 case 33072: hurt
= 33073; heal
= 33074; break;
1443 sLog
.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo
->Id
);
1447 if(m_caster
->IsFriendlyTo(unitTarget
))
1448 m_caster
->CastSpell(unitTarget
, heal
, true, 0);
1450 m_caster
->CastSpell(unitTarget
, hurt
, true, 0);
1454 case 561: // Judgement of command
1459 uint32 spell_id
= m_currentBasePoints
[i
]+1;
1460 SpellEntry
const* spell_proto
= sSpellStore
.LookupEntry(spell_id
);
1464 if( !unitTarget
->hasUnitState(UNIT_STAT_STUNNED
) && m_caster
->GetTypeId()==TYPEID_PLAYER
)
1466 // decreased damage (/2) for non-stunned target.
1467 SpellModifier
*mod
= new SpellModifier
;
1468 mod
->op
= SPELLMOD_DAMAGE
;
1470 mod
->type
= SPELLMOD_PCT
;
1471 mod
->spellId
= m_spellInfo
->Id
;
1473 mod
->lastAffected
= NULL
;
1474 mod
->mask
= 0x0000020000000000LL
;
1477 ((Player
*)m_caster
)->AddSpellMod(mod
, true);
1478 m_caster
->CastSpell(unitTarget
,spell_proto
,true,NULL
);
1480 ((Player
*)m_caster
)->AddSpellMod(mod
, false);
1483 m_caster
->CastSpell(unitTarget
,spell_proto
,true,NULL
);
1489 switch(m_spellInfo
->Id
)
1491 case 31789: // Righteous Defense (step 1)
1493 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1495 // non-standard cast requirement check
1496 if (!unitTarget
|| unitTarget
->getAttackers().empty())
1498 // clear cooldown at fail
1499 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
1501 ((Player
*)m_caster
)->RemoveSpellCooldown(m_spellInfo
->Id
);
1503 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
1504 data
<< uint32(m_spellInfo
->Id
);
1505 data
<< uint64(m_caster
->GetGUID());
1506 ((Player
*)m_caster
)->GetSession()->SendPacket(&data
);
1509 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT
);
1513 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1514 // Clear targets for eff 1
1515 for(std::list
<TargetInfo
>::iterator ihit
= m_UniqueTargetInfo
.begin();ihit
!= m_UniqueTargetInfo
.end();++ihit
)
1516 ihit
->effectMask
&= ~(1<<1);
1518 // not empty (checked)
1519 Unit::AttackerSet
const& attackers
= unitTarget
->getAttackers();
1521 // chance to be selected from list
1522 float chance
= 100.0f
/attackers
.size();
1524 for(Unit::AttackerSet::const_iterator aItr
= attackers
.begin(); aItr
!= attackers
.end() && count
< 3; ++aItr
)
1526 if(!roll_chance_f(chance
))
1529 AddUnitTarget((*aItr
), 1);
1532 // now let next effect cast spell at each target.
1535 case 37877: // Blessing of Faith
1540 uint32 spell_id
= 0;
1541 switch(unitTarget
->getClass())
1543 case CLASS_DRUID
: spell_id
= 37878; break;
1544 case CLASS_PALADIN
: spell_id
= 37879; break;
1545 case CLASS_PRIEST
: spell_id
= 37880; break;
1546 case CLASS_SHAMAN
: spell_id
= 37881; break;
1547 default: return; // ignore for not healing classes
1550 m_caster
->CastSpell(m_caster
,spell_id
,true);
1555 case SPELLFAMILY_SHAMAN
:
1556 //Shaman Rockbiter Weapon
1557 if (m_spellInfo
->SpellFamilyFlags
== 0x400000)
1559 uint32 spell_id
= 0;
1560 switch(m_spellInfo
->Id
)
1562 case 8017: spell_id
= 36494; break; // Rank 1
1563 case 8018: spell_id
= 36750; break; // Rank 2
1564 case 8019: spell_id
= 36755; break; // Rank 3
1565 case 10399: spell_id
= 36759; break; // Rank 4
1566 case 16314: spell_id
= 36763; break; // Rank 5
1567 case 16315: spell_id
= 36766; break; // Rank 6
1568 case 16316: spell_id
= 36771; break; // Rank 7
1569 case 25479: spell_id
= 36775; break; // Rank 8
1570 case 25485: spell_id
= 36499; break; // Rank 9
1572 sLog
.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo
->Id
);
1576 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( spell_id
);
1580 sLog
.outError("WORLD: unknown spell id %i\n", spell_id
);
1584 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
1587 for(int i
= BASE_ATTACK
; i
<= OFF_ATTACK
; ++i
)
1589 if(Item
* item
= ((Player
*)m_caster
)->GetWeaponForAttack(WeaponAttackType(i
)))
1591 if(item
->IsFitToSpellRequirements(m_spellInfo
))
1593 Spell
*spell
= new Spell(m_caster
, spellInfo
, true);
1595 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1596 // at calculation applied affect from Elemental Weapons talent
1597 // real enchantment damage-1
1598 spell
->m_currentBasePoints
[1] = damage
-1;
1600 SpellCastTargets targets
;
1601 targets
.setItemTarget( item
);
1602 spell
->prepare(&targets
);
1609 if(m_spellInfo
->Id
== 39610) // Mana-Tide Totem effect
1611 if(!unitTarget
|| unitTarget
->getPowerType() != POWER_MANA
)
1614 // Regenerate 6% of Total Mana Every 3 secs
1615 int32 EffectBasePoints0
= unitTarget
->GetMaxPower(POWER_MANA
) * damage
/ 100;
1616 m_caster
->CastCustomSpell(unitTarget
,39609,&EffectBasePoints0
,NULL
,NULL
,true,NULL
,NULL
,m_originalCasterGUID
);
1624 if(PetAura
const* petSpell
= spellmgr
.GetPetAura(m_spellInfo
->Id
))
1626 m_caster
->AddPetAura(petSpell
);
1631 void Spell::EffectTriggerSpellWithValue(uint32 i
)
1633 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1636 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1640 sLog
.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo
->Id
,triggered_spell_id
);
1645 m_caster
->CastCustomSpell(unitTarget
,triggered_spell_id
,&bp
,&bp
,&bp
,true,NULL
,NULL
,m_originalCasterGUID
);
1648 void Spell::EffectTriggerRitualOfSummoning(uint32 i
)
1650 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1651 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1655 sLog
.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
1660 Spell
*spell
= new Spell(m_caster
, spellInfo
, true);
1662 SpellCastTargets targets
;
1663 targets
.setUnitTarget( unitTarget
);
1664 spell
->prepare(&targets
);
1666 m_caster
->SetCurrentCastedSpell(spell
);
1667 spell
->m_selfContainer
= &(m_caster
->m_currentSpells
[spell
->GetCurrentContainer()]);
1671 void Spell::EffectForceCast(uint32 i
)
1676 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1679 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1683 sLog
.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
1687 unitTarget
->CastSpell(unitTarget
,spellInfo
,true,NULL
,NULL
,m_originalCasterGUID
);
1690 void Spell::EffectTriggerSpell(uint32 i
)
1692 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[i
];
1695 switch(triggered_spell_id
)
1700 m_caster
->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT
);
1701 m_caster
->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED
);
1702 m_caster
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED
);
1704 // if this spell is given to NPC it must handle rest by it's own AI
1705 if ( m_caster
->GetTypeId() != TYPEID_PLAYER
)
1708 // get highest rank of the Stealth spell
1710 const PlayerSpellMap
& sp_list
= ((Player
*)m_caster
)->GetSpellMap();
1711 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
1713 // only highest rank is shown in spell book, so simply check if shown in spell book
1714 if(!itr
->second
->active
|| itr
->second
->disabled
|| itr
->second
->state
== PLAYERSPELL_REMOVED
)
1717 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
1721 if (spellInfo
->SpellFamilyName
== SPELLFAMILY_ROGUE
&& spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE_STEALTH
)
1723 spellId
= spellInfo
->Id
;
1728 // no Stealth spell found
1732 // reset cooldown on it if needed
1733 if(((Player
*)m_caster
)->HasSpellCooldown(spellId
))
1734 ((Player
*)m_caster
)->RemoveSpellCooldown(spellId
);
1736 m_caster
->CastSpell(m_caster
, spellId
, true);
1740 case 23770: // Sayge's Dark Fortune of *
1741 // not exist, common cooldown can be implemented in scripts if need.
1743 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1746 const SpellEntry
*spell
= sSpellStore
.LookupEntry(24575);
1750 for (int i
=0; i
< spell
->StackAmount
; ++i
)
1751 m_caster
->CastSpell(unitTarget
,spell
->Id
, true, m_CastItem
, NULL
, m_originalCasterGUID
);
1754 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1757 const SpellEntry
*spell
= sSpellStore
.LookupEntry(26464);
1761 for (int i
=0; i
< spell
->StackAmount
; ++i
)
1762 m_caster
->CastSpell(unitTarget
,spell
->Id
, true, m_CastItem
, NULL
, m_originalCasterGUID
);
1765 // Righteous Defense
1768 m_caster
->CastSpell(unitTarget
, 31790, true,m_CastItem
,NULL
,m_originalCasterGUID
);
1774 Unit::AuraMap
& Auras
= m_caster
->GetAuras();
1775 for(Unit::AuraMap::iterator iter
= Auras
.begin(); iter
!= Auras
.end(); ++iter
)
1777 // remove all harmful spells on you...
1778 if( // ignore positive and passive auras
1779 !iter
->second
->IsPositive() && !iter
->second
->IsPassive() &&
1780 // ignore physical auras
1781 (GetSpellSchoolMask(iter
->second
->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL
)==0 &&
1782 // ignore immunity persistent spells
1783 !( iter
->second
->GetSpellProto()->AttributesEx
& 0x10000 ) )
1785 m_caster
->RemoveAurasDueToSpell(iter
->second
->GetSpellProto()->Id
);
1786 iter
= Auras
.begin();
1791 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1794 if (Unit
*pet
= m_caster
->GetPet())
1795 pet
->CastSpell(pet
, 28305, true);
1801 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1805 sLog
.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo
->Id
,triggered_spell_id
);
1809 // some triggered spells require specific equipment
1810 if(spellInfo
->EquippedItemClass
>=0 && m_caster
->GetTypeId()==TYPEID_PLAYER
)
1812 // main hand weapon required
1813 if(spellInfo
->AttributesEx3
& SPELL_ATTR_EX3_MAIN_HAND
)
1815 Item
* item
= ((Player
*)m_caster
)->GetWeaponForAttack(BASE_ATTACK
);
1817 // skip spell if no weapon in slot or broken
1818 if(!item
|| item
->IsBroken() )
1821 // skip spell if weapon not fit to triggered spell
1822 if(!item
->IsFitToSpellRequirements(spellInfo
))
1826 // offhand hand weapon required
1827 if(spellInfo
->AttributesEx3
& SPELL_ATTR_EX3_REQ_OFFHAND
)
1829 Item
* item
= ((Player
*)m_caster
)->GetWeaponForAttack(OFF_ATTACK
);
1831 // skip spell if no weapon in slot or broken
1832 if(!item
|| item
->IsBroken() )
1835 // skip spell if weapon not fit to triggered spell
1836 if(!item
->IsFitToSpellRequirements(spellInfo
))
1841 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1842 bool instant
= false;
1843 for(uint32 j
= i
+1; j
< 3; ++j
)
1845 if(m_spellInfo
->Effect
[j
]==SPELL_EFFECT_INSTAKILL
&& m_spellInfo
->EffectImplicitTargetA
[j
]==TARGET_SELF
)
1855 m_caster
->CastSpell(unitTarget
,spellInfo
,true,m_CastItem
,NULL
,m_originalCasterGUID
);
1858 m_TriggerSpells
.push_back(spellInfo
);
1861 void Spell::EffectTriggerMissileSpell(uint32 effect_idx
)
1863 uint32 triggered_spell_id
= m_spellInfo
->EffectTriggerSpell
[effect_idx
];
1866 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry( triggered_spell_id
);
1870 sLog
.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1871 m_spellInfo
->Id
,effect_idx
,triggered_spell_id
);
1876 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1878 Spell
*spell
= new Spell(m_caster
, spellInfo
, true, m_originalCasterGUID
);
1880 SpellCastTargets targets
;
1881 targets
.setDestination(m_targets
.m_destX
,m_targets
.m_destY
,m_targets
.m_destZ
);
1882 spell
->m_CastItem
= m_CastItem
;
1883 spell
->prepare(&targets
, NULL
);
1886 void Spell::EffectTeleportUnits(uint32 i
)
1888 if(!unitTarget
|| unitTarget
->isInFlight())
1891 switch (m_spellInfo
->EffectImplicitTargetB
[i
])
1893 case TARGET_INNKEEPER_COORDINATES
:
1895 // Only players can teleport to innkeeper
1896 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
1899 ((Player
*)unitTarget
)->TeleportTo(((Player
*)unitTarget
)->m_homebindMapId
,((Player
*)unitTarget
)->m_homebindX
,((Player
*)unitTarget
)->m_homebindY
,((Player
*)unitTarget
)->m_homebindZ
,unitTarget
->GetOrientation(),unitTarget
==m_caster
? TELE_TO_SPELL
: 0);
1902 case TARGET_TABLE_X_Y_Z_COORDINATES
:
1904 // TODO: Only players can teleport?
1905 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
1907 SpellTargetPosition
const* st
= spellmgr
.GetSpellTargetPosition(m_spellInfo
->Id
);
1910 sLog
.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo
->Id
);
1913 ((Player
*)unitTarget
)->TeleportTo(st
->target_mapId
,st
->target_X
,st
->target_Y
,st
->target_Z
,st
->target_Orientation
,unitTarget
==m_caster
? TELE_TO_SPELL
: 0);
1916 case TARGET_BEHIND_VICTIM
:
1918 // Get selected target for player (or victim for units)
1919 Unit
*pTarget
= NULL
;
1920 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
1921 pTarget
= ObjectAccessor::GetUnit(*m_caster
, ((Player
*)m_caster
)->GetSelection());
1923 pTarget
= m_caster
->getVictim();
1924 // No target present - return
1927 // Init dest coordinates
1928 uint32 mapid
= m_caster
->GetMapId();
1929 float x
= m_targets
.m_destX
;
1930 float y
= m_targets
.m_destY
;
1931 float z
= m_targets
.m_destZ
;
1932 float orientation
= pTarget
->GetOrientation();
1934 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
1935 ((Player
*)unitTarget
)->TeleportTo(mapid
, x
, y
, z
, orientation
, TELE_TO_NOT_LEAVE_COMBAT
| TELE_TO_NOT_UNSUMMON_PET
| (unitTarget
==m_caster
? TELE_TO_SPELL
: 0));
1938 m_caster
->GetMap()->CreatureRelocation((Creature
*)unitTarget
, x
, y
, z
, orientation
);
1940 unitTarget
->BuildTeleportAckMsg(&data
, x
, y
, z
, orientation
);
1941 unitTarget
->SendMessageToSet(&data
, false);
1947 // If not exist data for dest location - return
1948 if(!(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
))
1950 sLog
.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i
, m_spellInfo
->EffectImplicitTargetB
[i
], m_spellInfo
->Id
);
1953 // Init dest coordinates
1954 uint32 mapid
= m_caster
->GetMapId();
1955 float x
= m_targets
.m_destX
;
1956 float y
= m_targets
.m_destY
;
1957 float z
= m_targets
.m_destZ
;
1958 float orientation
= unitTarget
->GetOrientation();
1960 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
1961 ((Player
*)unitTarget
)->TeleportTo(mapid
, x
, y
, z
, orientation
, TELE_TO_NOT_LEAVE_COMBAT
| TELE_TO_NOT_UNSUMMON_PET
| (unitTarget
==m_caster
? TELE_TO_SPELL
: 0));
1964 m_caster
->GetMap()->CreatureRelocation((Creature
*)unitTarget
, x
, y
, z
, orientation
);
1966 unitTarget
->BuildTeleportAckMsg(&data
, x
, y
, z
, orientation
);
1967 unitTarget
->SendMessageToSet(&data
, false);
1973 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1974 switch ( m_spellInfo
->Id
)
1976 // Dimensional Ripper - Everlook
1979 int32 r
= irand(0, 119);
1980 if ( r
>= 70 ) // 7/12 success
1982 if ( r
< 100 ) // 4/12 evil twin
1983 m_caster
->CastSpell(m_caster
,23445,true);
1985 m_caster
->CastSpell(m_caster
,23449,true);
1989 // Ultrasafe Transporter: Toshley's Station
1992 if ( roll_chance_i(50) ) // 50% success
1994 int32 rand_eff
= urand(1,7);
1998 // soul split - evil
1999 m_caster
->CastSpell(m_caster
,36900,true);
2002 // soul split - good
2003 m_caster
->CastSpell(m_caster
,36901,true);
2006 // Increase the size
2007 m_caster
->CastSpell(m_caster
,36895,true);
2010 // Decrease the size
2011 m_caster
->CastSpell(m_caster
,36893,true);
2016 if (((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
2017 m_caster
->CastSpell(m_caster
,36897,true);
2019 m_caster
->CastSpell(m_caster
,36899,true);
2024 m_caster
->CastSpell(m_caster
,36940,true);
2028 m_caster
->CastSpell(m_caster
,23445,true);
2034 // Dimensional Ripper - Area 52
2037 if ( roll_chance_i(50) ) // 50% success
2039 int32 rand_eff
= urand(1,4);
2043 // soul split - evil
2044 m_caster
->CastSpell(m_caster
,36900,true);
2047 // soul split - good
2048 m_caster
->CastSpell(m_caster
,36901,true);
2051 // Increase the size
2052 m_caster
->CastSpell(m_caster
,36895,true);
2057 if (((Player
*)m_caster
)->GetTeam() == ALLIANCE
)
2058 m_caster
->CastSpell(m_caster
,36897,true);
2060 m_caster
->CastSpell(m_caster
,36899,true);
2070 void Spell::EffectApplyAura(uint32 i
)
2075 SpellImmuneList
const& list
= unitTarget
->m_spellImmune
[IMMUNITY_STATE
];
2076 for(SpellImmuneList::const_iterator itr
= list
.begin(); itr
!= list
.end(); ++itr
)
2077 if(itr
->type
== m_spellInfo
->EffectApplyAuraName
[i
])
2080 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2081 if( !unitTarget
->isAlive() && m_spellInfo
->Id
!= 20584 && m_spellInfo
->Id
!= 8326 &&
2082 (unitTarget
->GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)unitTarget
)->GetSession()->PlayerLoading()) )
2085 Unit
* caster
= m_originalCasterGUID
? m_originalCaster
: m_caster
;
2089 sLog
.outDebug("Spell: Aura is: %u", m_spellInfo
->EffectApplyAuraName
[i
]);
2091 Aura
* Aur
= CreateAura(m_spellInfo
, i
, &m_currentBasePoints
[i
], unitTarget
, caster
, m_CastItem
);
2093 // Now Reduce spell duration using data received at spell hit
2094 int32 duration
= Aur
->GetAuraMaxDuration();
2095 unitTarget
->ApplyDiminishingToDuration(m_diminishGroup
,duration
,m_caster
,m_diminishLevel
);
2096 Aur
->setDiminishGroup(m_diminishGroup
);
2098 // if Aura removed and deleted, do not continue.
2099 if(duration
== 0 && !(Aur
->IsPermanent()))
2105 if(duration
!= Aur
->GetAuraMaxDuration())
2107 Aur
->SetAuraMaxDuration(duration
);
2108 Aur
->SetAuraDuration(duration
);
2111 bool added
= unitTarget
->AddAura(Aur
);
2113 // Aura not added and deleted in AddAura call;
2117 // found crash at character loading, broken pointer to Aur...
2118 // Aur was deleted in AddAura()...
2122 // TODO Make a way so it works for every related spell!
2123 if(unitTarget
->GetTypeId()==TYPEID_PLAYER
) // Negative buff should only be applied on players
2126 if(m_spellInfo
->CasterAuraStateNot
==AURA_STATE_WEAKENED_SOUL
|| m_spellInfo
->TargetAuraStateNot
==AURA_STATE_WEAKENED_SOUL
)
2127 spellId
= 6788; // Weakened Soul
2128 else if(m_spellInfo
->CasterAuraStateNot
==AURA_STATE_FORBEARANCE
|| m_spellInfo
->TargetAuraStateNot
==AURA_STATE_FORBEARANCE
)
2129 spellId
= 25771; // Forbearance
2130 else if(m_spellInfo
->CasterAuraStateNot
==AURA_STATE_HYPOTHERMIA
)
2131 spellId
= 41425; // Hypothermia
2132 else if (m_spellInfo
->Mechanic
== MECHANIC_BANDAGE
) // Bandages
2133 spellId
= 11196; // Recently Bandaged
2134 else if( (m_spellInfo
->AttributesEx
& 0x20) && (m_spellInfo
->AttributesEx2
& 0x20000) )
2135 spellId
= 23230; // Blood Fury - Healing Reduction
2137 SpellEntry
const *AdditionalSpellInfo
= sSpellStore
.LookupEntry(spellId
);
2138 if (AdditionalSpellInfo
)
2140 // applied at target by target
2141 Aura
* AdditionalAura
= CreateAura(AdditionalSpellInfo
, 0, &m_currentBasePoints
[0], unitTarget
,unitTarget
, 0);
2142 unitTarget
->AddAura(AdditionalAura
);
2143 sLog
.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo
->EffectApplyAuraName
[0]);
2147 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2148 if( m_spellInfo
->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (m_spellInfo
->SpellFamilyFlags
& 0x00002000000000LL
))
2149 m_caster
->CastSpell(unitTarget
, 41637, true, NULL
, Aur
, m_originalCasterGUID
);
2152 void Spell::EffectUnlearnSpecialization( uint32 i
)
2154 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
2157 Player
*_player
= (Player
*)unitTarget
;
2158 uint32 spellToUnlearn
= m_spellInfo
->EffectTriggerSpell
[i
];
2160 _player
->removeSpell(spellToUnlearn
);
2162 sLog
.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player
->GetGUIDLow(), spellToUnlearn
, m_caster
->GetGUIDLow() );
2165 void Spell::EffectPowerDrain(uint32 i
)
2167 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2170 Powers drain_power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2174 if(!unitTarget
->isAlive())
2176 if(unitTarget
->getPowerType() != drain_power
)
2181 uint32 curPower
= unitTarget
->GetPower(drain_power
);
2183 //add spell damage bonus
2184 damage
=m_caster
->SpellDamageBonus(unitTarget
,m_spellInfo
,uint32(damage
),SPELL_DIRECT_DAMAGE
);
2186 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2187 uint32 power
= damage
;
2188 if ( drain_power
== POWER_MANA
&& unitTarget
->GetTypeId() == TYPEID_PLAYER
)
2189 power
-= ((Player
*)unitTarget
)->GetSpellCritDamageReduction(power
);
2192 if(curPower
< power
)
2193 new_damage
= curPower
;
2197 unitTarget
->ModifyPower(drain_power
,-new_damage
);
2199 if(drain_power
== POWER_MANA
)
2201 float manaMultiplier
= m_spellInfo
->EffectMultipleValue
[i
];
2202 if(manaMultiplier
==0)
2205 if(Player
*modOwner
= m_caster
->GetSpellModOwner())
2206 modOwner
->ApplySpellMod(m_spellInfo
->Id
, SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
2208 int32 gain
= int32(new_damage
*manaMultiplier
);
2210 m_caster
->ModifyPower(POWER_MANA
,gain
);
2212 m_caster
->SendEnergizeSpellLog(m_caster
, m_spellInfo
->Id
,gain
,POWER_MANA
);
2216 void Spell::EffectSendEvent(uint32 EffectIndex
)
2218 if (m_caster
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)m_caster
)->InBattleGround())
2220 BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround();
2221 if(bg
&& bg
->GetStatus() == STATUS_IN_PROGRESS
)
2223 switch(m_spellInfo
->Id
)
2225 case 23333: // Pickup Horde Flag
2226 /*do not uncomment .
2227 if(bg->GetTypeID()==BATTLEGROUND_WS)
2228 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2229 sLog.outDebug("Send Event Horde Flag Picked Up");
2232 case 23334: // Drop Horde Flag
2233 if(bg->GetTypeID()==BATTLEGROUND_WS)
2234 bg->EventPlayerDroppedFlag((Player*)m_caster);
2235 sLog.outDebug("Drop Horde Flag");
2238 case 23335: // Pickup Alliance Flag
2239 /*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
2240 if(bg->GetTypeID()==BATTLEGROUND_WS)
2241 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2242 sLog.outDebug("Send Event Alliance Flag Picked Up");
2245 case 23336: // Drop Alliance Flag
2246 if(bg->GetTypeID()==BATTLEGROUND_WS)
2247 bg->EventPlayerDroppedFlag((Player*)m_caster);
2248 sLog.outDebug("Drop Alliance Flag");
2250 case 23385: // Alliance Flag Returns
2251 if(bg->GetTypeID()==BATTLEGROUND_WS)
2252 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2253 sLog.outDebug("Alliance Flag Returned");
2255 case 23386: // Horde Flag Returns
2256 if(bg->GetTypeID()==BATTLEGROUND_WS)
2257 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2258 sLog.outDebug("Horde Flag Returned");
2262 if(bg->GetTypeID()==BATTLEGROUND_EY)
2263 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2267 sLog
.outDebug("Unknown spellid %u in BG event", m_spellInfo
->Id
);
2272 sLog
.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo
->EffectMiscValue
[EffectIndex
], m_spellInfo
->Id
);
2273 sWorld
.ScriptsStart(sEventScripts
, m_spellInfo
->EffectMiscValue
[EffectIndex
], m_caster
, focusObject
);
2276 void Spell::EffectPowerBurn(uint32 i
)
2278 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2281 Powers powertype
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2285 if(!unitTarget
->isAlive())
2287 if(unitTarget
->getPowerType()!=powertype
)
2292 int32 curPower
= int32(unitTarget
->GetPower(powertype
));
2294 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2295 uint32 power
= damage
;
2296 if ( powertype
== POWER_MANA
&& unitTarget
->GetTypeId() == TYPEID_PLAYER
)
2297 power
-= ((Player
*)unitTarget
)->GetSpellCritDamageReduction(power
);
2299 int32 new_damage
= (curPower
< power
) ? curPower
: power
;
2301 unitTarget
->ModifyPower(powertype
,-new_damage
);
2302 float multiplier
= m_spellInfo
->EffectMultipleValue
[i
];
2304 if(Player
*modOwner
= m_caster
->GetSpellModOwner())
2305 modOwner
->ApplySpellMod(m_spellInfo
->Id
, SPELLMOD_MULTIPLE_VALUE
, multiplier
);
2307 new_damage
= int32(new_damage
*multiplier
);
2308 m_damage
+=new_damage
;
2311 void Spell::EffectHeal( uint32
/*i*/ )
2313 if( unitTarget
&& unitTarget
->isAlive() && damage
>= 0)
2315 // Try to get original caster
2316 Unit
*caster
= m_originalCasterGUID
? m_originalCaster
: m_caster
;
2318 // Skip if m_originalCaster not available
2322 int32 addhealth
= damage
;
2324 // Vessel of the Naaru (Vial of the Sunwell trinket)
2325 if (m_spellInfo
->Id
== 45064)
2327 // Amount of heal - depends from stacked Holy Energy
2328 int damageAmount
= 0;
2329 Unit::AuraList
const& mDummyAuras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
2330 for(Unit::AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
2331 if((*i
)->GetId() == 45062)
2332 damageAmount
+=(*i
)->GetModifier()->m_amount
;
2334 m_caster
->RemoveAurasDueToSpell(45062);
2336 addhealth
+= damageAmount
;
2338 // Swiftmend - consumes Regrowth or Rejuvenation
2339 else if (m_spellInfo
->TargetAuraState
== AURA_STATE_SWIFTMEND
&& unitTarget
->HasAuraState(AURA_STATE_SWIFTMEND
))
2341 Unit::AuraList
const& RejorRegr
= unitTarget
->GetAurasByType(SPELL_AURA_PERIODIC_HEAL
);
2342 // find most short by duration
2343 Aura
*targetAura
= NULL
;
2344 for(Unit::AuraList::const_iterator i
= RejorRegr
.begin(); i
!= RejorRegr
.end(); ++i
)
2346 if((*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_DRUID
2347 && ((*i
)->GetSpellProto()->SpellFamilyFlags
== 0x40 || (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x10) )
2349 if(!targetAura
|| (*i
)->GetAuraDuration() < targetAura
->GetAuraDuration())
2356 sLog
.outError("Target(GUID:" I64FMTD
") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget
->GetGUID());
2362 if(targetAura
->GetSpellProto()->EffectApplyAuraName
[idx
] == SPELL_AURA_PERIODIC_HEAL
)
2367 int32 tickheal
= caster
->SpellHealingBonus(targetAura
->GetSpellProto(), targetAura
->GetModifier()->m_amount
, DOT
, unitTarget
);
2368 int32 tickcount
= GetSpellDuration(targetAura
->GetSpellProto()) / targetAura
->GetSpellProto()->EffectAmplitude
[idx
];
2369 unitTarget
->RemoveAurasDueToSpell(targetAura
->GetId());
2371 addhealth
+= tickheal
* tickcount
;
2374 addhealth
= caster
->SpellHealingBonus(m_spellInfo
, addhealth
,HEAL
, unitTarget
);
2376 m_healing
+=addhealth
;
2380 void Spell::EffectHealPct( uint32
/*i*/ )
2382 if( unitTarget
&& unitTarget
->isAlive() && damage
>= 0)
2384 // Try to get original caster
2385 Unit
*caster
= m_originalCasterGUID
? m_originalCaster
: m_caster
;
2387 // Skip if m_originalCaster not available
2391 uint32 addhealth
= unitTarget
->GetMaxHealth() * damage
/ 100;
2392 caster
->SendHealSpellLog(unitTarget
, m_spellInfo
->Id
, addhealth
, false);
2394 int32 gain
= unitTarget
->ModifyHealth( int32(addhealth
) );
2395 unitTarget
->getHostilRefManager().threatAssist(m_caster
, float(gain
) * 0.5f
, m_spellInfo
);
2397 if(caster
->GetTypeId()==TYPEID_PLAYER
)
2398 if(BattleGround
*bg
= ((Player
*)caster
)->GetBattleGround())
2399 bg
->UpdatePlayerScore(((Player
*)caster
), SCORE_HEALING_DONE
, gain
);
2403 void Spell::EffectHealMechanical( uint32
/*i*/ )
2405 // Mechanic creature type should be correctly checked by targetCreatureType field
2406 if( unitTarget
&& unitTarget
->isAlive() && damage
>= 0)
2408 // Try to get original caster
2409 Unit
*caster
= m_originalCasterGUID
? m_originalCaster
: m_caster
;
2411 // Skip if m_originalCaster not available
2415 uint32 addhealth
= caster
->SpellHealingBonus(m_spellInfo
, uint32(damage
), HEAL
, unitTarget
);
2416 caster
->SendHealSpellLog(unitTarget
, m_spellInfo
->Id
, addhealth
, false);
2417 unitTarget
->ModifyHealth( int32(damage
) );
2421 void Spell::EffectHealthLeech(uint32 i
)
2425 if(!unitTarget
->isAlive())
2431 sLog
.outDebug("HealthLeech :%i", damage
);
2433 float multiplier
= m_spellInfo
->EffectMultipleValue
[i
];
2435 if(Player
*modOwner
= m_caster
->GetSpellModOwner())
2436 modOwner
->ApplySpellMod(m_spellInfo
->Id
, SPELLMOD_MULTIPLE_VALUE
, multiplier
);
2438 int32 new_damage
= int32(damage
*multiplier
);
2439 uint32 curHealth
= unitTarget
->GetHealth();
2440 new_damage
= m_caster
->SpellNonMeleeDamageLog(unitTarget
, m_spellInfo
->Id
, new_damage
, m_IsTriggeredSpell
, true);
2441 if(curHealth
< new_damage
)
2442 new_damage
= curHealth
;
2444 if(m_caster
->isAlive())
2446 new_damage
= m_caster
->SpellHealingBonus(m_spellInfo
, new_damage
, HEAL
, m_caster
);
2448 m_caster
->ModifyHealth(new_damage
);
2450 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
2451 m_caster
->SendHealSpellLog(m_caster
, m_spellInfo
->Id
, uint32(new_damage
));
2453 // m_healthLeech+=tmpvalue;
2454 // m_damage+=new_damage;
2457 void Spell::DoCreateItem(uint32 i
, uint32 itemtype
)
2459 if (!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
2462 Player
* player
= (Player
*)unitTarget
;
2464 uint32 newitemid
= itemtype
;
2465 ItemPrototype
const *pProto
= objmgr
.GetItemPrototype( newitemid
);
2468 player
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, NULL
, NULL
);
2474 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2475 if(pProto
->Class
!= ITEM_CLASS_CONSUMABLE
|| m_spellInfo
->SpellFamilyName
!= SPELLFAMILY_MAGE
)
2477 int32 basePoints
= m_currentBasePoints
[i
];
2478 int32 randomPoints
= m_spellInfo
->EffectDieSides
[i
];
2480 num_to_add
= basePoints
+ irand(1, randomPoints
);
2482 num_to_add
= basePoints
+ 1;
2484 else if (pProto
->MaxCount
== 1)
2486 else if(player
->getLevel() >= m_spellInfo
->spellLevel
)
2488 int32 basePoints
= m_currentBasePoints
[i
];
2489 float pointPerLevel
= m_spellInfo
->EffectRealPointsPerLevel
[i
];
2490 num_to_add
= basePoints
+ 1 + uint32((player
->getLevel() - m_spellInfo
->spellLevel
)*pointPerLevel
);
2497 if (num_to_add
> pProto
->Stackable
)
2498 num_to_add
= pProto
->Stackable
;
2500 // init items_count to 1, since 1 item will be created regardless of specialization
2502 // the chance to create additional items
2503 float additionalCreateChance
=0.0f
;
2504 // the maximum number of created additional items
2505 uint8 additionalMaxNum
=0;
2506 // get the chance and maximum number for creating extra items
2507 if ( canCreateExtraItems(player
, m_spellInfo
->Id
, additionalCreateChance
, additionalMaxNum
) )
2509 // roll with this chance till we roll not to create or we create the max num
2510 while ( roll_chance_f(additionalCreateChance
) && items_count
<=additionalMaxNum
)
2514 // really will be created more items
2515 num_to_add
*= items_count
;
2517 // can the player store the new item?
2518 ItemPosCountVec dest
;
2519 uint32 no_space
= 0;
2520 uint8 msg
= player
->CanStoreNewItem( NULL_BAG
, NULL_SLOT
, dest
, newitemid
, num_to_add
, &no_space
);
2521 if( msg
!= EQUIP_ERR_OK
)
2523 // convert to possible store amount
2524 if( msg
== EQUIP_ERR_INVENTORY_FULL
|| msg
== EQUIP_ERR_CANT_CARRY_MORE_OF_THIS
)
2525 num_to_add
-= no_space
;
2528 // if not created by another reason from full inventory or unique items amount limitation
2529 player
->SendEquipError( msg
, NULL
, NULL
);
2536 // create the new item and store it
2537 Item
* pItem
= player
->StoreNewItem( dest
, newitemid
, true, Item::GenerateItemRandomPropertyId(newitemid
));
2539 // was it successful? return error if not
2542 player
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, NULL
, NULL
);
2546 // set the "Crafted by ..." property of the item
2547 if( pItem
->GetProto()->Class
!= ITEM_CLASS_CONSUMABLE
&& pItem
->GetProto()->Class
!= ITEM_CLASS_QUEST
)
2548 pItem
->SetUInt32Value(ITEM_FIELD_CREATOR
,player
->GetGUIDLow());
2550 // send info to the client
2552 player
->SendNewItem(pItem
, num_to_add
, true, true);
2554 // we succeeded in creating at least one item, so a levelup is possible
2555 player
->UpdateCraftSkill(m_spellInfo
->Id
);
2558 // for battleground marks send by mail if not add all expected
2561 BattleGroundTypeId bgType
;
2562 switch(m_spellInfo
->Id
)
2564 case SPELL_AV_MARK_WINNER
:
2565 case SPELL_AV_MARK_LOSER
:
2566 bgType
= BATTLEGROUND_AV
;
2568 case SPELL_WS_MARK_WINNER
:
2569 case SPELL_WS_MARK_LOSER
:
2570 bgType
= BATTLEGROUND_WS
;
2572 case SPELL_AB_MARK_WINNER
:
2573 case SPELL_AB_MARK_LOSER
:
2574 bgType
= BATTLEGROUND_AB
;
2580 if(BattleGround
* bg
= sBattleGroundMgr
.GetBattleGround(bgType
))
2581 bg
->SendRewardMarkByMail(player
,newitemid
,no_space
);
2585 void Spell::EffectCreateItem(uint32 i
)
2587 DoCreateItem(i
,m_spellInfo
->EffectItemType
[i
]);
2590 void Spell::EffectPersistentAA(uint32 i
)
2592 float radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
2594 if(Player
* modOwner
= m_caster
->GetSpellModOwner())
2595 modOwner
->ApplySpellMod(m_spellInfo
->Id
, SPELLMOD_RADIUS
, radius
);
2597 int32 duration
= GetSpellDuration(m_spellInfo
);
2598 DynamicObject
* dynObj
= new DynamicObject
;
2599 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
))
2604 dynObj
->SetUInt32Value(OBJECT_FIELD_TYPE
, 65);
2605 dynObj
->SetUInt32Value(GAMEOBJECT_DISPLAYID
, 368003);
2606 dynObj
->SetUInt32Value(DYNAMICOBJECT_BYTES
, 0x01eeeeee);
2607 m_caster
->AddDynObject(dynObj
);
2608 dynObj
->GetMap()->Add(dynObj
);
2611 void Spell::EffectEnergize(uint32 i
)
2615 if(!unitTarget
->isAlive())
2618 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2621 // Some level depends spells
2624 switch (m_spellInfo
->Id
)
2628 level_diff
= m_caster
->getLevel() - 40;
2633 level_diff
= m_caster
->getLevel() - 60;
2638 level_diff
= m_caster
->getLevel() - 60;
2646 damage
-= multiplier
* level_diff
;
2651 Powers power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2653 if(unitTarget
->GetMaxPower(power
) == 0)
2656 unitTarget
->ModifyPower(power
,damage
);
2657 m_caster
->SendEnergizeSpellLog(unitTarget
, m_spellInfo
->Id
, damage
, power
);
2659 // Mad Alchemist's Potion
2660 if (m_spellInfo
->Id
== 45051)
2662 // find elixirs on target
2663 uint32 elixir_mask
= 0;
2664 Unit::AuraMap
& Auras
= unitTarget
->GetAuras();
2665 for(Unit::AuraMap::iterator itr
= Auras
.begin(); itr
!= Auras
.end(); ++itr
)
2667 uint32 spell_id
= itr
->second
->GetId();
2668 if(uint32 mask
= spellmgr
.GetSpellElixirMask(spell_id
))
2669 elixir_mask
|= mask
;
2672 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2673 elixir_mask
= (elixir_mask
& ELIXIR_FLASK_MASK
) ^ ELIXIR_FLASK_MASK
;
2675 // get all available elixirs by mask and spell level
2676 std::vector
<uint32
> elixirs
;
2677 SpellElixirMap
const& m_spellElixirs
= spellmgr
.GetSpellElixirMap();
2678 for(SpellElixirMap::const_iterator itr
= m_spellElixirs
.begin(); itr
!= m_spellElixirs
.end(); ++itr
)
2680 if (itr
->second
& elixir_mask
)
2682 if (itr
->second
& (ELIXIR_UNSTABLE_MASK
| ELIXIR_SHATTRATH_MASK
))
2685 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
2686 if (spellInfo
&& (spellInfo
->spellLevel
< m_spellInfo
->spellLevel
|| spellInfo
->spellLevel
> unitTarget
->getLevel()))
2689 elixirs
.push_back(itr
->first
);
2693 if (!elixirs
.empty())
2695 // cast random elixir on target
2696 uint32 rand_spell
= urand(0,elixirs
.size()-1);
2697 m_caster
->CastSpell(unitTarget
,elixirs
[rand_spell
],true,m_CastItem
);
2702 void Spell::EffectEnergisePct(uint32 i
)
2706 if(!unitTarget
->isAlive())
2709 if(m_spellInfo
->EffectMiscValue
[i
] < 0 || m_spellInfo
->EffectMiscValue
[i
] >= MAX_POWERS
)
2712 Powers power
= Powers(m_spellInfo
->EffectMiscValue
[i
]);
2714 uint32 maxPower
= unitTarget
->GetMaxPower(power
);
2718 uint32 gain
= damage
* maxPower
/ 100;
2719 unitTarget
->ModifyPower(power
, gain
);
2720 m_caster
->SendEnergizeSpellLog(unitTarget
, m_spellInfo
->Id
, damage
, power
);
2723 void Spell::SendLoot(uint64 guid
, LootType loottype
)
2725 Player
* player
= (Player
*)m_caster
;
2731 if (Script
->GOHello(player
, gameObjTarget
))
2734 switch (gameObjTarget
->GetGoType())
2736 case GAMEOBJECT_TYPE_DOOR
:
2737 case GAMEOBJECT_TYPE_BUTTON
:
2738 gameObjTarget
->UseDoorOrButton();
2739 sWorld
.ScriptsStart(sGameObjectScripts
, gameObjTarget
->GetDBTableGUIDLow(), player
, gameObjTarget
);
2742 case GAMEOBJECT_TYPE_QUESTGIVER
:
2743 // start or end quest
2744 player
->PrepareQuestMenu(guid
);
2745 player
->SendPreparedQuest(guid
);
2748 case GAMEOBJECT_TYPE_SPELL_FOCUS
:
2749 // triggering linked GO
2750 if(uint32 trapEntry
= gameObjTarget
->GetGOInfo()->spellFocus
.linkedTrapId
)
2751 gameObjTarget
->TriggeringLinkedGameObject(trapEntry
,m_caster
);
2754 case GAMEOBJECT_TYPE_GOOBER
:
2755 // goober_scripts can be triggered if the player don't have the quest
2756 if (gameObjTarget
->GetGOInfo()->goober
.eventId
)
2758 sLog
.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget
->GetGOInfo()->goober
.eventId
,gameObjTarget
->GetDBTableGUIDLow());
2759 sWorld
.ScriptsStart(sEventScripts
, gameObjTarget
->GetGOInfo()->goober
.eventId
, player
, gameObjTarget
);
2762 // cast goober spell
2763 if (gameObjTarget
->GetGOInfo()->goober
.questId
)
2764 ///Quest require to be active for GO using
2765 if(player
->GetQuestStatus(gameObjTarget
->GetGOInfo()->goober
.questId
) != QUEST_STATUS_INCOMPLETE
)
2768 gameObjTarget
->AddUniqueUse(player
);
2769 gameObjTarget
->SetLootState(GO_JUST_DEACTIVATED
);
2771 //TODO? Objective counting called without spell check but with quest objective check
2772 // if send spell id then this line will duplicate to spell casting call (double counting)
2773 // So we or have this line and not required in quest_template have reqSpellIdN
2774 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2775 player
->CastedCreatureOrGO(gameObjTarget
->GetEntry(), gameObjTarget
->GetGUID(), 0);
2777 // triggering linked GO
2778 if(uint32 trapEntry
= gameObjTarget
->GetGOInfo()->goober
.linkedTrapId
)
2779 gameObjTarget
->TriggeringLinkedGameObject(trapEntry
,m_caster
);
2783 case GAMEOBJECT_TYPE_CHEST
:
2784 // TODO: possible must be moved to loot release (in different from linked triggering)
2785 if (gameObjTarget
->GetGOInfo()->chest
.eventId
)
2787 sLog
.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget
->GetGOInfo()->chest
.eventId
,gameObjTarget
->GetDBTableGUIDLow());
2788 sWorld
.ScriptsStart(sEventScripts
, gameObjTarget
->GetGOInfo()->chest
.eventId
, player
, gameObjTarget
);
2791 // triggering linked GO
2792 if(uint32 trapEntry
= gameObjTarget
->GetGOInfo()->chest
.linkedTrapId
)
2793 gameObjTarget
->TriggeringLinkedGameObject(trapEntry
,m_caster
);
2795 // Don't return, let loots been taken
2800 player
->SendLoot(guid
, loottype
);
2803 void Spell::EffectOpenLock(uint32
/*i*/)
2805 if(!m_caster
|| m_caster
->GetTypeId() != TYPEID_PLAYER
)
2807 sLog
.outDebug( "WORLD: Open Lock - No Player Caster!");
2811 Player
* player
= (Player
*)m_caster
;
2813 LootType loottype
= LOOT_CORPSE
;
2820 GameObjectInfo
const* goInfo
= gameObjTarget
->GetGOInfo();
2821 // Arathi Basin banner opening !
2822 if( goInfo
->type
== GAMEOBJECT_TYPE_BUTTON
&& goInfo
->button
.noDamageImmune
||
2823 goInfo
->type
== GAMEOBJECT_TYPE_GOOBER
&& goInfo
->goober
.losOK
)
2825 //isAllowUseBattleGroundObject() already called in CanCast()
2826 // in battleground check
2827 if(BattleGround
*bg
= player
->GetBattleGround())
2829 // check if it's correct bg
2830 if(bg
&& bg
->GetTypeID() == BATTLEGROUND_AB
)
2831 bg
->EventPlayerClickedOnFlag(player
, gameObjTarget
);
2835 else if (goInfo
->type
== GAMEOBJECT_TYPE_FLAGSTAND
)
2837 //isAllowUseBattleGroundObject() already called in CanCast()
2838 // in battleground check
2839 if(BattleGround
*bg
= player
->GetBattleGround())
2841 if(bg
->GetTypeID() == BATTLEGROUND_EY
)
2842 bg
->EventPlayerClickedOnFlag(player
, gameObjTarget
);
2846 lockId
= gameObjTarget
->GetLockId();
2847 guid
= gameObjTarget
->GetGUID();
2851 lockId
= itemTarget
->GetProto()->LockID
;
2852 guid
= itemTarget
->GetGUID();
2856 sLog
.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2860 if(!lockId
) // possible case for GO and maybe for items.
2862 SendLoot(guid
, loottype
);
2867 LockEntry
const *lockInfo
= sLockStore
.LookupEntry(lockId
);
2871 sLog
.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2872 (gameObjTarget
? "gameobject" : "item"), GUID_LOPART(guid
), lockId
);
2873 SendCastResult(SPELL_FAILED_BAD_TARGETS
);
2878 for(int i
= 0; i
< 5; ++i
)
2880 // type==1 This means lockInfo->key[i] is an item
2881 if(lockInfo
->keytype
[i
]==LOCK_KEY_ITEM
&& lockInfo
->key
[i
] && m_CastItem
&& m_CastItem
->GetEntry()==lockInfo
->key
[i
])
2883 SendLoot(guid
, loottype
);
2889 // Check and skill-up skill
2890 if( m_spellInfo
->Effect
[1] == SPELL_EFFECT_SKILL
)
2891 SkillId
= m_spellInfo
->EffectMiscValue
[1];
2892 // pickpocketing spells
2893 else if( m_spellInfo
->EffectMiscValue
[0] == LOCKTYPE_PICKLOCK
)
2894 SkillId
= SKILL_LOCKPICKING
;
2896 // skill bonus provided by casting spell (mostly item spells)
2897 uint32 spellSkillBonus
= uint32(m_currentBasePoints
[0]+1);
2899 uint32 reqSkillValue
= lockInfo
->requiredminingskill
;
2901 if(lockInfo
->requiredlockskill
) // required pick lock skill applying
2903 if(SkillId
!= SKILL_LOCKPICKING
) // wrong skill (cheating?)
2905 SendCastResult(SPELL_FAILED_FIZZLE
);
2909 reqSkillValue
= lockInfo
->requiredlockskill
;
2911 else if(SkillId
== SKILL_LOCKPICKING
) // apply picklock skill to wrong target
2913 SendCastResult(SPELL_FAILED_BAD_TARGETS
);
2919 loottype
= LOOT_SKINNING
;
2920 if ( player
->GetSkillValue(SkillId
) + spellSkillBonus
< reqSkillValue
)
2922 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL
);
2926 // update skill if really known
2927 uint32 SkillValue
= player
->GetPureSkillValue(SkillId
);
2928 if(SkillValue
) // non only item base skill
2932 // Allow one skill-up until respawned
2933 if ( !gameObjTarget
->IsInSkillupList( player
->GetGUIDLow() ) &&
2934 player
->UpdateGatherSkill(SkillId
, SkillValue
, reqSkillValue
) )
2935 gameObjTarget
->AddToSkillupList( player
->GetGUIDLow() );
2940 uint32 SkillValue
= player
->GetPureSkillValue(SkillId
);
2941 player
->UpdateGatherSkill(SkillId
, SkillValue
, reqSkillValue
);
2946 SendLoot(guid
, loottype
);
2949 void Spell::EffectSummonChangeItem(uint32 i
)
2951 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
2954 Player
*player
= (Player
*)m_caster
;
2956 // applied only to using item
2960 // ... only to item in own inventory/bank/equip_slot
2961 if(m_CastItem
->GetOwnerGUID()!=player
->GetGUID())
2964 uint32 newitemid
= m_spellInfo
->EffectItemType
[i
];
2968 uint16 pos
= m_CastItem
->GetPos();
2970 Item
*pNewItem
= Item::CreateItem( newitemid
, 1, player
);
2974 for(uint8 i
= PERM_ENCHANTMENT_SLOT
; i
<=TEMP_ENCHANTMENT_SLOT
; ++i
)
2976 if(m_CastItem
->GetEnchantmentId(EnchantmentSlot(i
)))
2977 pNewItem
->SetEnchantment(EnchantmentSlot(i
), m_CastItem
->GetEnchantmentId(EnchantmentSlot(i
)), m_CastItem
->GetEnchantmentDuration(EnchantmentSlot(i
)), m_CastItem
->GetEnchantmentCharges(EnchantmentSlot(i
)));
2980 if(m_CastItem
->GetUInt32Value(ITEM_FIELD_DURABILITY
) < m_CastItem
->GetUInt32Value(ITEM_FIELD_MAXDURABILITY
))
2982 double loosePercent
= 1 - m_CastItem
->GetUInt32Value(ITEM_FIELD_DURABILITY
) / double(m_CastItem
->GetUInt32Value(ITEM_FIELD_MAXDURABILITY
));
2983 player
->DurabilityLoss(pNewItem
, loosePercent
);
2986 if( player
->IsInventoryPos( pos
) )
2988 ItemPosCountVec dest
;
2989 uint8 msg
= player
->CanStoreItem( m_CastItem
->GetBagSlot(), m_CastItem
->GetSlot(), dest
, pNewItem
, true );
2990 if( msg
== EQUIP_ERR_OK
)
2992 player
->DestroyItem(m_CastItem
->GetBagSlot(), m_CastItem
->GetSlot(),true);
2994 // prevent crash at access and unexpected charges counting with item update queue corrupt
2995 if(m_CastItem
==m_targets
.getItemTarget())
2996 m_targets
.setItemTarget(NULL
);
3000 player
->StoreItem( dest
, pNewItem
, true);
3004 else if( player
->IsBankPos ( pos
) )
3006 ItemPosCountVec dest
;
3007 uint8 msg
= player
->CanBankItem( m_CastItem
->GetBagSlot(), m_CastItem
->GetSlot(), dest
, pNewItem
, true );
3008 if( msg
== EQUIP_ERR_OK
)
3010 player
->DestroyItem(m_CastItem
->GetBagSlot(), m_CastItem
->GetSlot(),true);
3012 // prevent crash at access and unexpected charges counting with item update queue corrupt
3013 if(m_CastItem
==m_targets
.getItemTarget())
3014 m_targets
.setItemTarget(NULL
);
3018 player
->BankItem( dest
, pNewItem
, true);
3022 else if( player
->IsEquipmentPos ( pos
) )
3025 uint8 msg
= player
->CanEquipItem( m_CastItem
->GetSlot(), dest
, pNewItem
, true );
3026 if( msg
== EQUIP_ERR_OK
)
3028 player
->DestroyItem(m_CastItem
->GetBagSlot(), m_CastItem
->GetSlot(),true);
3030 // prevent crash at access and unexpected charges counting with item update queue corrupt
3031 if(m_CastItem
==m_targets
.getItemTarget())
3032 m_targets
.setItemTarget(NULL
);
3036 player
->EquipItem( dest
, pNewItem
, true);
3037 player
->AutoUnequipOffhandIfNeed();
3046 void Spell::EffectOpenSecretSafe(uint32 i
)
3048 EffectOpenLock(i
); //no difference for now
3051 void Spell::EffectProficiency(uint32
/*i*/)
3053 if (!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3055 Player
*p_target
= (Player
*)unitTarget
;
3057 uint32 subClassMask
= m_spellInfo
->EquippedItemSubClassMask
;
3058 if(m_spellInfo
->EquippedItemClass
== 2 && !(p_target
->GetWeaponProficiency() & subClassMask
))
3060 p_target
->AddWeaponProficiency(subClassMask
);
3061 p_target
->SendProficiency(uint8(0x02),p_target
->GetWeaponProficiency());
3063 if(m_spellInfo
->EquippedItemClass
== 4 && !(p_target
->GetArmorProficiency() & subClassMask
))
3065 p_target
->AddArmorProficiency(subClassMask
);
3066 p_target
->SendProficiency(uint8(0x04),p_target
->GetArmorProficiency());
3070 void Spell::EffectApplyAreaAura(uint32 i
)
3074 if(!unitTarget
->isAlive())
3077 AreaAura
* Aur
= new AreaAura(m_spellInfo
, i
, &m_currentBasePoints
[i
], unitTarget
, m_caster
, m_CastItem
);
3078 unitTarget
->AddAura(Aur
);
3081 void Spell::EffectSummonType(uint32 i
)
3083 switch(m_spellInfo
->EffectMiscValueB
[i
])
3085 case SUMMON_TYPE_GUARDIAN
:
3086 case SUMMON_TYPE_POSESSED
:
3087 case SUMMON_TYPE_POSESSED2
:
3088 EffectSummonGuardian(i
);
3090 case SUMMON_TYPE_WILD
:
3091 EffectSummonWild(i
);
3093 case SUMMON_TYPE_DEMON
:
3094 EffectSummonDemon(i
);
3096 case SUMMON_TYPE_SUMMON
:
3099 case SUMMON_TYPE_CRITTER
:
3100 case SUMMON_TYPE_CRITTER2
:
3101 case SUMMON_TYPE_CRITTER3
:
3102 EffectSummonCritter(i
);
3104 case SUMMON_TYPE_TOTEM_SLOT1
:
3105 case SUMMON_TYPE_TOTEM_SLOT2
:
3106 case SUMMON_TYPE_TOTEM_SLOT3
:
3107 case SUMMON_TYPE_TOTEM_SLOT4
:
3108 case SUMMON_TYPE_TOTEM
:
3109 EffectSummonTotem(i
);
3111 case SUMMON_TYPE_UNKNOWN1
:
3112 case SUMMON_TYPE_UNKNOWN2
:
3113 case SUMMON_TYPE_UNKNOWN3
:
3114 case SUMMON_TYPE_UNKNOWN4
:
3115 case SUMMON_TYPE_UNKNOWN5
:
3118 sLog
.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo
->EffectMiscValueB
[i
]);
3123 void Spell::EffectSummon(uint32 i
)
3125 if(m_caster
->GetPetGUID())
3130 uint32 pet_entry
= m_spellInfo
->EffectMiscValue
[i
];
3133 uint32 level
= m_caster
->getLevel();
3134 Pet
* spawnCreature
= new Pet(SUMMON_PET
);
3136 if(spawnCreature
->LoadPetFromDB(m_caster
,pet_entry
))
3138 // set timer for unsummon
3139 int32 duration
= GetSpellDuration(m_spellInfo
);
3141 spawnCreature
->SetDuration(duration
);
3146 Map
*map
= m_caster
->GetMap();
3147 uint32 pet_number
= objmgr
.GeneratePetNumber();
3148 if(!spawnCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
),map
,m_spellInfo
->EffectMiscValue
[i
], pet_number
))
3150 sLog
.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo
->EffectMiscValue
[i
]);
3151 delete spawnCreature
;
3155 // Summon in dest location
3157 if(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
3159 x
= m_targets
.m_destX
;
3160 y
= m_targets
.m_destY
;
3161 z
= m_targets
.m_destZ
;
3164 m_caster
->GetClosePoint(x
,y
,z
,spawnCreature
->GetObjectSize());
3166 spawnCreature
->Relocate(x
,y
,z
,-m_caster
->GetOrientation());
3168 if(!spawnCreature
->IsPositionValid())
3170 sLog
.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3171 spawnCreature
->GetGUIDLow(), spawnCreature
->GetEntry(), spawnCreature
->GetPositionX(), spawnCreature
->GetPositionY());
3172 delete spawnCreature
;
3176 // set timer for unsummon
3177 int32 duration
= GetSpellDuration(m_spellInfo
);
3179 spawnCreature
->SetDuration(duration
);
3181 spawnCreature
->SetOwnerGUID(m_caster
->GetGUID());
3182 spawnCreature
->SetUInt32Value(UNIT_NPC_FLAGS
, 0);
3183 spawnCreature
->setPowerType(POWER_MANA
);
3184 spawnCreature
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, m_caster
->getFaction());
3185 spawnCreature
->SetUInt32Value(UNIT_FIELD_FLAGS
, 0);
3186 spawnCreature
->SetUInt32Value(UNIT_FIELD_BYTES_0
, 2048);
3187 spawnCreature
->SetUInt32Value(UNIT_FIELD_BYTES_1
, 0);
3188 spawnCreature
->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP
, 0);
3189 spawnCreature
->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE
, 0);
3190 spawnCreature
->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP
, 1000);
3191 spawnCreature
->SetCreatorGUID(m_caster
->GetGUID());
3192 spawnCreature
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
3194 spawnCreature
->InitStatsForLevel(level
);
3196 spawnCreature
->GetCharmInfo()->SetPetNumber(pet_number
, false);
3198 spawnCreature
->AIM_Initialize();
3199 spawnCreature
->InitPetCreateSpells();
3200 spawnCreature
->SetHealth(spawnCreature
->GetMaxHealth());
3201 spawnCreature
->SetPower(POWER_MANA
, spawnCreature
->GetMaxPower(POWER_MANA
));
3203 std::string name
= m_caster
->GetName();
3204 name
.append(petTypeSuffix
[spawnCreature
->getPetType()]);
3205 spawnCreature
->SetName( name
);
3207 map
->Add((Creature
*)spawnCreature
);
3209 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3211 m_caster
->SetPet(spawnCreature
);
3212 spawnCreature
->GetCharmInfo()->SetReactState( REACT_DEFENSIVE
);
3213 spawnCreature
->SavePetToDB(PET_SAVE_AS_CURRENT
);
3214 ((Player
*)m_caster
)->PetSpellInitialize();
3218 void Spell::EffectLearnSpell(uint32 i
)
3223 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3225 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3226 EffectLearnPetSpell(i
);
3231 Player
*player
= (Player
*)unitTarget
;
3233 uint32 spellToLearn
= (m_spellInfo
->Id
==SPELL_ID_GENERIC_LEARN
) ? damage
: m_spellInfo
->EffectTriggerSpell
[i
];
3234 player
->learnSpell(spellToLearn
);
3236 sLog
.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player
->GetGUIDLow(), spellToLearn
, m_caster
->GetGUIDLow() );
3239 void Spell::EffectDispel(uint32 i
)
3244 // Fill possible dispell list
3245 std::vector
<Aura
*> dispel_list
;
3247 // Create dispel mask by dispel type
3248 uint32 dispel_type
= m_spellInfo
->EffectMiscValue
[i
];
3249 uint32 dispelMask
= GetDispellMask( DispelType(dispel_type
) );
3250 Unit::AuraMap
const& auras
= unitTarget
->GetAuras();
3251 for(Unit::AuraMap::const_iterator itr
= auras
.begin(); itr
!= auras
.end(); ++itr
)
3253 Aura
*aur
= (*itr
).second
;
3254 if (aur
&& (1<<aur
->GetSpellProto()->Dispel
) & dispelMask
)
3256 if(aur
->GetSpellProto()->Dispel
== DISPEL_MAGIC
)
3258 bool positive
= true;
3259 if (!aur
->IsPositive())
3262 positive
= (aur
->GetSpellProto()->AttributesEx
& SPELL_ATTR_EX_NEGATIVE
)==0;
3264 // do not remove positive auras if friendly target
3265 // negative auras if non-friendly target
3266 if(positive
== unitTarget
->IsFriendlyTo(m_caster
))
3269 // Add aura to dispel list
3270 dispel_list
.push_back(aur
);
3273 // Ok if exist some buffs for dispel try dispel it
3274 if (!dispel_list
.empty())
3276 std::list
< std::pair
<uint32
,uint64
> > success_list
;// (spell_id,casterGuid)
3277 std::list
< uint32
> fail_list
; // spell_id
3278 int32 list_size
= dispel_list
.size();
3279 // Dispell N = damage buffs (or while exist buffs for dispel)
3280 for (int32 count
=0; count
< damage
&& list_size
> 0; ++count
)
3282 // Random select buff for dispel
3283 Aura
*aur
= dispel_list
[urand(0, list_size
-1)];
3285 SpellEntry
const* spellInfo
= aur
->GetSpellProto();
3286 // Base dispel chance
3287 // TODO: possible chance depend from spell level??
3288 int32 miss_chance
= 0;
3289 // Apply dispel mod from aura caster
3290 if (Unit
*caster
= aur
->GetCaster())
3292 if ( Player
* modOwner
= caster
->GetSpellModOwner() )
3293 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_RESIST_DISPEL_CHANCE
, miss_chance
, this);
3296 if (roll_chance_i(miss_chance
))
3297 fail_list
.push_back(aur
->GetId());
3299 success_list
.push_back(std::pair
<uint32
,uint64
>(aur
->GetId(),aur
->GetCasterGUID()));
3300 // Remove buff from list for prevent doubles
3301 for (std::vector
<Aura
*>::iterator j
= dispel_list
.begin(); j
!= dispel_list
.end(); )
3303 Aura
*dispeled
= *j
;
3304 if (dispeled
->GetId() == aur
->GetId() && dispeled
->GetCasterGUID() == aur
->GetCasterGUID())
3306 j
= dispel_list
.erase(j
);
3313 // Send success log and really remove auras
3314 if (!success_list
.empty())
3316 int32 count
= success_list
.size();
3317 WorldPacket
data(SMSG_SPELLDISPELLOG
, 8+8+4+1+4+count
*5);
3318 data
.append(unitTarget
->GetPackGUID()); // Victim GUID
3319 data
.append(m_caster
->GetPackGUID()); // Caster GUID
3320 data
<< uint32(m_spellInfo
->Id
); // Dispell spell id
3321 data
<< uint8(0); // not used
3322 data
<< uint32(count
); // count
3323 for (std::list
<std::pair
<uint32
,uint64
> >::iterator j
= success_list
.begin(); j
!= success_list
.end(); ++j
)
3325 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(j
->first
);
3326 data
<< uint32(spellInfo
->Id
); // Spell Id
3327 data
<< uint8(0); // 0 - dispeled !=0 cleansed
3328 unitTarget
->RemoveAurasDueToSpellByDispel(spellInfo
->Id
, j
->second
, m_caster
);
3330 m_caster
->SendMessageToSet(&data
, true);
3334 if (m_spellInfo
->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& m_spellInfo
->Category
== 12)
3336 uint32 heal_spell
= 0;
3337 switch (m_spellInfo
->Id
)
3339 case 19505: heal_spell
= 19658; break;
3340 case 19731: heal_spell
= 19732; break;
3341 case 19734: heal_spell
= 19733; break;
3342 case 19736: heal_spell
= 19735; break;
3343 case 27276: heal_spell
= 27278; break;
3344 case 27277: heal_spell
= 27279; break;
3346 sLog
.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo
->Id
);
3350 m_caster
->CastSpell(m_caster
, heal_spell
, true);
3353 // Send fail log to client
3354 if (!fail_list
.empty())
3356 // Failed to dispell
3357 WorldPacket
data(SMSG_DISPEL_FAILED
, 8+8+4+4*fail_list
.size());
3358 data
<< uint64(m_caster
->GetGUID()); // Caster GUID
3359 data
<< uint64(unitTarget
->GetGUID()); // Victim GUID
3360 data
<< uint32(m_spellInfo
->Id
); // Dispell spell id
3361 for (std::list
< uint32
>::iterator j
= fail_list
.begin(); j
!= fail_list
.end(); ++j
)
3362 data
<< uint32(*j
); // Spell Id
3363 m_caster
->SendMessageToSet(&data
, true);
3368 void Spell::EffectDualWield(uint32
/*i*/)
3370 if (unitTarget
->GetTypeId() == TYPEID_PLAYER
)
3371 ((Player
*)unitTarget
)->SetCanDualWield(true);
3374 void Spell::EffectPull(uint32
/*i*/)
3376 // TODO: create a proper pull towards distract spell center for distract
3377 sLog
.outDebug("WORLD: Spell Effect DUMMY");
3380 void Spell::EffectDistract(uint32
/*i*/)
3382 // Check for possible target
3383 if (!unitTarget
|| unitTarget
->isInCombat())
3386 // target must be OK to do this
3387 if( unitTarget
->hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) )
3390 float angle
= unitTarget
->GetAngle(m_targets
.m_destX
, m_targets
.m_destY
);
3392 if ( unitTarget
->GetTypeId() == TYPEID_PLAYER
)
3394 // For players just turn them
3396 ((Player
*)unitTarget
)->BuildTeleportAckMsg(&data
, unitTarget
->GetPositionX(), unitTarget
->GetPositionY(), unitTarget
->GetPositionZ(), angle
);
3397 ((Player
*)unitTarget
)->GetSession()->SendPacket( &data
);
3398 ((Player
*)unitTarget
)->SetPosition(unitTarget
->GetPositionX(), unitTarget
->GetPositionY(), unitTarget
->GetPositionZ(), angle
, false);
3402 // Set creature Distracted, Stop it, And turn it
3403 unitTarget
->SetOrientation(angle
);
3404 unitTarget
->StopMoving();
3405 unitTarget
->GetMotionMaster()->MoveDistract(damage
*1000);
3409 void Spell::EffectPickPocket(uint32
/*i*/)
3411 if( m_caster
->GetTypeId() != TYPEID_PLAYER
)
3414 // victim must be creature and attackable
3415 if( !unitTarget
|| unitTarget
->GetTypeId() != TYPEID_UNIT
|| m_caster
->IsFriendlyTo(unitTarget
) )
3418 // victim have to be alive and humanoid or undead
3419 if( unitTarget
->isAlive() && (unitTarget
->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD
) != 0)
3421 int32 chance
= 10 + int32(m_caster
->getLevel()) - int32(unitTarget
->getLevel());
3423 if (chance
> irand(0, 19))
3425 // Stealing successful
3426 //sLog.outDebug("Sending loot from pickpocket");
3427 ((Player
*)m_caster
)->SendLoot(unitTarget
->GetGUID(),LOOT_PICKPOCKETING
);
3431 // Reveal action + get attack
3432 m_caster
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
3433 if (((Creature
*)unitTarget
)->AI())
3434 ((Creature
*)unitTarget
)->AI()->AttackStart(m_caster
);
3439 void Spell::EffectAddFarsight(uint32 i
)
3441 float radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
3442 int32 duration
= GetSpellDuration(m_spellInfo
);
3443 DynamicObject
* dynObj
= new DynamicObject
;
3444 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
))
3449 dynObj
->SetUInt32Value(OBJECT_FIELD_TYPE
, 65);
3450 dynObj
->SetUInt32Value(DYNAMICOBJECT_BYTES
, 0x80000002);
3451 m_caster
->AddDynObject(dynObj
);
3452 dynObj
->GetMap()->Add(dynObj
);
3453 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3454 ((Player
*)m_caster
)->SetFarSight(dynObj
->GetGUID());
3457 void Spell::EffectSummonWild(uint32 i
)
3459 uint32 creature_entry
= m_spellInfo
->EffectMiscValue
[i
];
3463 uint32 level
= m_caster
->getLevel();
3465 // level of creature summoned using engineering item based at engineering skill level
3466 if(m_caster
->GetTypeId()==TYPEID_PLAYER
&& m_CastItem
)
3468 ItemPrototype
const *proto
= m_CastItem
->GetProto();
3469 if(proto
&& proto
->RequiredSkill
== SKILL_ENGINERING
)
3471 uint16 skill202
= ((Player
*)m_caster
)->GetSkillValue(SKILL_ENGINERING
);
3479 // select center of summon position
3480 float center_x
= m_targets
.m_destX
;
3481 float center_y
= m_targets
.m_destY
;
3482 float center_z
= m_targets
.m_destZ
;
3484 float radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
3486 int32 amount
= damage
> 0 ? damage
: 1;
3488 for(int32 count
= 0; count
< amount
; ++count
)
3491 // If dest location if present
3492 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
3494 // Summon 1 unit in dest location
3497 px
= m_targets
.m_destX
;
3498 py
= m_targets
.m_destY
;
3499 pz
= m_targets
.m_destZ
;
3501 // Summon in random point all other units if location present
3503 m_caster
->GetRandomPoint(center_x
,center_y
,center_z
,radius
,px
,py
,pz
);
3505 // Summon if dest location not present near caster
3507 m_caster
->GetClosePoint(px
,py
,pz
,3.0f
);
3509 int32 duration
= GetSpellDuration(m_spellInfo
);
3511 TempSummonType summonType
= (duration
== 0) ? TEMPSUMMON_DEAD_DESPAWN
: TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
;
3513 m_caster
->SummonCreature(creature_entry
,px
,py
,pz
,m_caster
->GetOrientation(),summonType
,duration
);
3517 void Spell::EffectSummonGuardian(uint32 i
)
3519 uint32 pet_entry
= m_spellInfo
->EffectMiscValue
[i
];
3523 // Jewelery statue case (totem like)
3524 if(m_spellInfo
->SpellIconID
==2056)
3526 EffectSummonTotem(i
);
3530 // set timer for unsummon
3531 int32 duration
= GetSpellDuration(m_spellInfo
);
3533 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3534 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3535 // so this code hack in fact
3536 if( m_caster
->GetTypeId() == TYPEID_PLAYER
&& (duration
<= 0 || GetSpellRecoveryTime(m_spellInfo
)==0) )
3537 if(((Player
*)m_caster
)->HasGuardianWithEntry(pet_entry
))
3538 return; // find old guardian, ignore summon
3540 // in another case summon new
3541 uint32 level
= m_caster
->getLevel();
3543 // level of pet summoned using engineering item based at engineering skill level
3544 if(m_caster
->GetTypeId()==TYPEID_PLAYER
&& m_CastItem
)
3546 ItemPrototype
const *proto
= m_CastItem
->GetProto();
3547 if(proto
&& proto
->RequiredSkill
== SKILL_ENGINERING
)
3549 uint16 skill202
= ((Player
*)m_caster
)->GetSkillValue(SKILL_ENGINERING
);
3557 // select center of summon position
3558 float center_x
= m_targets
.m_destX
;
3559 float center_y
= m_targets
.m_destY
;
3560 float center_z
= m_targets
.m_destZ
;
3562 float radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
3564 int32 amount
= damage
> 0 ? damage
: 1;
3566 for(int32 count
= 0; count
< amount
; ++count
)
3568 Pet
* spawnCreature
= new Pet(GUARDIAN_PET
);
3570 Map
*map
= m_caster
->GetMap();
3571 uint32 pet_number
= objmgr
.GeneratePetNumber();
3572 if(!spawnCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
), map
,m_spellInfo
->EffectMiscValue
[i
], pet_number
))
3574 sLog
.outError("no such creature entry %u",m_spellInfo
->EffectMiscValue
[i
]);
3575 delete spawnCreature
;
3580 // If dest location if present
3581 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
3583 // Summon 1 unit in dest location
3586 px
= m_targets
.m_destX
;
3587 py
= m_targets
.m_destY
;
3588 pz
= m_targets
.m_destZ
;
3590 // Summon in random point all other units if location present
3592 m_caster
->GetRandomPoint(center_x
,center_y
,center_z
,radius
,px
,py
,pz
);
3594 // Summon if dest location not present near caster
3596 m_caster
->GetClosePoint(px
,py
,pz
,spawnCreature
->GetObjectSize());
3598 spawnCreature
->Relocate(px
,py
,pz
,m_caster
->GetOrientation());
3600 if(!spawnCreature
->IsPositionValid())
3602 sLog
.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3603 spawnCreature
->GetGUIDLow(), spawnCreature
->GetEntry(), spawnCreature
->GetPositionX(), spawnCreature
->GetPositionY());
3604 delete spawnCreature
;
3609 spawnCreature
->SetDuration(duration
);
3611 spawnCreature
->SetOwnerGUID(m_caster
->GetGUID());
3612 spawnCreature
->setPowerType(POWER_MANA
);
3613 spawnCreature
->SetUInt32Value(UNIT_NPC_FLAGS
, 0);
3614 spawnCreature
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,m_caster
->getFaction());
3615 spawnCreature
->SetUInt32Value(UNIT_FIELD_FLAGS
,0);
3616 spawnCreature
->SetUInt32Value(UNIT_FIELD_BYTES_1
,0);
3617 spawnCreature
->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP
,0);
3618 spawnCreature
->SetCreatorGUID(m_caster
->GetGUID());
3619 spawnCreature
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
3621 spawnCreature
->InitStatsForLevel(level
);
3622 spawnCreature
->GetCharmInfo()->SetPetNumber(pet_number
, false);
3624 spawnCreature
->AIM_Initialize();
3626 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
3627 ((Player
*)m_caster
)->AddGuardian(spawnCreature
);
3629 map
->Add((Creature
*)spawnCreature
);
3633 void Spell::EffectTeleUnitsFaceCaster(uint32 i
)
3638 if(unitTarget
->isInFlight())
3641 uint32 mapid
= m_caster
->GetMapId();
3642 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
3645 m_caster
->GetClosePoint(fx
,fy
,fz
,unitTarget
->GetObjectSize(),dis
);
3647 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
3648 ((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));
3650 m_caster
->GetMap()->CreatureRelocation((Creature
*)m_caster
, fx
, fy
, fz
, -m_caster
->GetOrientation());
3653 void Spell::EffectLearnSkill(uint32 i
)
3655 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3661 uint32 skillid
= m_spellInfo
->EffectMiscValue
[i
];
3662 uint16 skillval
= ((Player
*)unitTarget
)->GetPureSkillValue(skillid
);
3663 ((Player
*)unitTarget
)->SetSkill(skillid
, skillval
?skillval
:1, damage
*75);
3666 void Spell::EffectAddHonor(uint32
/*i*/)
3668 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3671 sLog
.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo
->Id
, damage
, ((Player
*)unitTarget
)->GetGUIDLow());
3673 // TODO: find formula for honor reward based on player's level!
3675 // now fixed only for level 70 players:
3676 if (((Player
*)unitTarget
)->getLevel() == 70)
3677 ((Player
*)unitTarget
)->RewardHonor(NULL
, 1, damage
);
3680 void Spell::EffectTradeSkill(uint32
/*i*/)
3682 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
3684 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3685 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3686 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3689 void Spell::EffectEnchantItemPerm(uint32 i
)
3691 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
3696 Player
* p_caster
= (Player
*)m_caster
;
3698 p_caster
->UpdateCraftSkill(m_spellInfo
->Id
);
3700 if (m_spellInfo
->EffectMiscValue
[i
])
3702 uint32 enchant_id
= m_spellInfo
->EffectMiscValue
[i
];
3704 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
3708 // item can be in trade slot and have owner diff. from caster
3709 Player
* item_owner
= itemTarget
->GetOwner();
3713 if(item_owner
!=p_caster
&& p_caster
->GetSession()->GetSecurity() > SEC_PLAYER
&& sWorld
.getConfig(CONFIG_GM_LOG_TRADE
) )
3715 sLog
.outCommand(p_caster
->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3716 p_caster
->GetName(),p_caster
->GetSession()->GetAccountId(),
3717 itemTarget
->GetProto()->Name1
,itemTarget
->GetEntry(),
3718 item_owner
->GetName(),item_owner
->GetSession()->GetAccountId());
3721 // remove old enchanting before applying new if equipped
3722 item_owner
->ApplyEnchantment(itemTarget
,PERM_ENCHANTMENT_SLOT
,false);
3724 itemTarget
->SetEnchantment(PERM_ENCHANTMENT_SLOT
, enchant_id
, 0, 0);
3726 // add new enchanting if equipped
3727 item_owner
->ApplyEnchantment(itemTarget
,PERM_ENCHANTMENT_SLOT
,true);
3731 void Spell::EffectEnchantItemTmp(uint32 i
)
3733 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
3736 Player
* p_caster
= (Player
*)m_caster
;
3741 uint32 enchant_id
= m_spellInfo
->EffectMiscValue
[i
];
3743 // Shaman Rockbiter Weapon
3744 if(i
==0 && m_spellInfo
->Effect
[1]==SPELL_EFFECT_DUMMY
)
3746 int32 enchnting_damage
= m_currentBasePoints
[1]+1;
3748 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3749 // with already applied percent bonus from Elemental Weapons talent
3750 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3751 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3752 switch(enchnting_damage
)
3755 case 2: enchant_id
= 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3757 case 4: enchant_id
= 6; break; // 0% [ 7% == 4, 14% == 4]
3758 case 5: enchant_id
= 3025; break; // 20%
3760 case 6: enchant_id
= 1; break; // 0% [ 7% == 6, 14% == 6]
3761 case 7: enchant_id
= 3027; break; // 20%
3763 case 9: enchant_id
= 3032; break; // 0% [ 7% == 6]
3764 case 10: enchant_id
= 503; break; // 14%
3765 case 11: enchant_id
= 3031; break; // 20%
3767 case 15: enchant_id
= 3035; break; // 0%
3768 case 16: enchant_id
= 1663; break; // 7%
3769 case 17: enchant_id
= 3033; break; // 14%
3770 case 18: enchant_id
= 3034; break; // 20%
3772 case 28: enchant_id
= 3038; break; // 0%
3773 case 29: enchant_id
= 683; break; // 7%
3774 case 31: enchant_id
= 3036; break; // 14%
3775 case 33: enchant_id
= 3037; break; // 20%
3777 case 40: enchant_id
= 3041; break; // 0%
3778 case 42: enchant_id
= 1664; break; // 7%
3779 case 45: enchant_id
= 3039; break; // 14%
3780 case 48: enchant_id
= 3040; break; // 20%
3782 case 49: enchant_id
= 3044; break; // 0%
3783 case 52: enchant_id
= 2632; break; // 7%
3784 case 55: enchant_id
= 3042; break; // 14%
3785 case 58: enchant_id
= 3043; break; // 20%
3787 case 62: enchant_id
= 2633; break; // 0%
3788 case 66: enchant_id
= 3018; break; // 7%
3789 case 70: enchant_id
= 3019; break; // 14%
3790 case 74: enchant_id
= 3020; break; // 20%
3792 sLog
.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage
);
3799 sLog
.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo
->Id
,i
);
3803 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
3806 sLog
.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo
->Id
,i
,enchant_id
);
3810 // select enchantment duration
3813 // rogue family enchantments exception by duration
3814 if(m_spellInfo
->Id
==38615)
3815 duration
= 1800; // 30 mins
3816 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3817 else if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
)
3818 duration
= 3600; // 1 hour
3819 // shaman family enchantments
3820 else if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_SHAMAN
)
3821 duration
= 1800; // 30 mins
3822 // other cases with this SpellVisual already selected
3823 else if(m_spellInfo
->SpellVisual
==215)
3824 duration
= 1800; // 30 mins
3825 // some fishing pole bonuses
3826 else if(m_spellInfo
->SpellVisual
==563)
3827 duration
= 600; // 10 mins
3828 // shaman rockbiter enchantments
3829 else if(m_spellInfo
->SpellVisual
==0)
3830 duration
= 1800; // 30 mins
3831 else if(m_spellInfo
->Id
==29702)
3832 duration
= 300; // 5 mins
3833 else if(m_spellInfo
->Id
==37360)
3834 duration
= 300; // 5 mins
3837 duration
= 3600; // 1 hour
3839 // item can be in trade slot and have owner diff. from caster
3840 Player
* item_owner
= itemTarget
->GetOwner();
3844 if(item_owner
!=p_caster
&& p_caster
->GetSession()->GetSecurity() > SEC_PLAYER
&& sWorld
.getConfig(CONFIG_GM_LOG_TRADE
) )
3846 sLog
.outCommand(p_caster
->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3847 p_caster
->GetName(),p_caster
->GetSession()->GetAccountId(),
3848 itemTarget
->GetProto()->Name1
,itemTarget
->GetEntry(),
3849 item_owner
->GetName(),item_owner
->GetSession()->GetAccountId());
3852 // remove old enchanting before applying new if equipped
3853 item_owner
->ApplyEnchantment(itemTarget
,TEMP_ENCHANTMENT_SLOT
,false);
3855 itemTarget
->SetEnchantment(TEMP_ENCHANTMENT_SLOT
, enchant_id
, duration
*1000, 0);
3857 // add new enchanting if equipped
3858 item_owner
->ApplyEnchantment(itemTarget
,TEMP_ENCHANTMENT_SLOT
,true);
3861 void Spell::EffectTameCreature(uint32
/*i*/)
3863 if(m_caster
->GetPetGUID())
3869 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
3872 Creature
* creatureTarget
= (Creature
*)unitTarget
;
3874 if(creatureTarget
->isPet())
3877 if(m_caster
->getClass() != CLASS_HUNTER
)
3880 // cast finish successfully
3881 //SendChannelUpdate(0);
3884 Pet
* pet
= m_caster
->CreateTamedPetFrom(creatureTarget
,m_spellInfo
->Id
);
3886 // kill original creature
3887 creatureTarget
->setDeathState(JUST_DIED
);
3888 creatureTarget
->RemoveCorpse();
3889 creatureTarget
->SetHealth(0); // just for nice GM-mode view
3891 // prepare visual effect for levelup
3892 pet
->SetUInt32Value(UNIT_FIELD_LEVEL
,creatureTarget
->getLevel()-1);
3895 pet
->GetMap()->Add((Creature
*)pet
);
3897 // visual effect for levelup
3898 pet
->SetUInt32Value(UNIT_FIELD_LEVEL
,creatureTarget
->getLevel());
3900 // caster have pet now
3901 m_caster
->SetPet(pet
);
3903 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3905 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
3906 ((Player
*)m_caster
)->PetSpellInitialize();
3910 void Spell::EffectSummonPet(uint32 i
)
3912 uint32 petentry
= m_spellInfo
->EffectMiscValue
[i
];
3914 Pet
*OldSummon
= m_caster
->GetPet();
3916 // if pet requested type already exist
3919 if(petentry
== 0 || OldSummon
->GetEntry() == petentry
)
3921 // pet in corpse state can't be summoned
3922 if( OldSummon
->isDead() )
3925 OldSummon
->GetMap()->Remove((Creature
*)OldSummon
,false);
3926 OldSummon
->SetMapId(m_caster
->GetMapId());
3929 m_caster
->GetClosePoint(px
, py
, pz
, OldSummon
->GetObjectSize());
3931 OldSummon
->Relocate(px
, py
, pz
, OldSummon
->GetOrientation());
3932 m_caster
->GetMap()->Add((Creature
*)OldSummon
);
3934 if(m_caster
->GetTypeId() == TYPEID_PLAYER
&& OldSummon
->isControlled() )
3936 ((Player
*)m_caster
)->PetSpellInitialize();
3941 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
3942 ((Player
*)m_caster
)->RemovePet(OldSummon
,(OldSummon
->getPetType()==HUNTER_PET
? PET_SAVE_AS_DELETED
: PET_SAVE_NOT_IN_SLOT
),false);
3947 Pet
* NewSummon
= new Pet
;
3949 // petentry==0 for hunter "call pet" (current pet summoned if any)
3950 if(NewSummon
->LoadPetFromDB(m_caster
,petentry
))
3952 if(NewSummon
->getPetType()==SUMMON_PET
)
3954 // Remove Demonic Sacrifice auras (known pet)
3955 Unit::AuraList
const& auraClassScripts
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
3956 for(Unit::AuraList::const_iterator itr
= auraClassScripts
.begin();itr
!=auraClassScripts
.end();)
3958 if((*itr
)->GetModifier()->m_miscvalue
==2228)
3960 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
3961 itr
= auraClassScripts
.begin();
3971 // not error in case fail hunter call pet
3978 CreatureInfo
const* cInfo
= sCreatureStorage
.LookupEntry
<CreatureInfo
>(petentry
);
3982 sLog
.outError("EffectSummonPet: creature entry %u not found.",petentry
);
3987 Map
*map
= m_caster
->GetMap();
3988 uint32 pet_number
= objmgr
.GeneratePetNumber();
3989 if(!NewSummon
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
), map
, petentry
, pet_number
))
3996 m_caster
->GetClosePoint(px
, py
, pz
, NewSummon
->GetObjectSize());
3998 NewSummon
->Relocate(px
, py
, pz
, m_caster
->GetOrientation());
4000 if(!NewSummon
->IsPositionValid())
4002 sLog
.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4003 NewSummon
->GetGUIDLow(), NewSummon
->GetEntry(), NewSummon
->GetPositionX(), NewSummon
->GetPositionY());
4008 uint32 petlevel
= m_caster
->getLevel();
4009 NewSummon
->setPetType(SUMMON_PET
);
4011 uint32 faction
= m_caster
->getFaction();
4012 if(m_caster
->GetTypeId() == TYPEID_UNIT
)
4014 if ( ((Creature
*)m_caster
)->isTotem() )
4015 NewSummon
->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE
);
4017 NewSummon
->GetCharmInfo()->SetReactState(REACT_DEFENSIVE
);
4020 NewSummon
->SetOwnerGUID(m_caster
->GetGUID());
4021 NewSummon
->SetCreatorGUID(m_caster
->GetGUID());
4022 NewSummon
->SetUInt32Value(UNIT_NPC_FLAGS
, 0);
4023 NewSummon
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, faction
);
4024 NewSummon
->SetUInt32Value(UNIT_FIELD_BYTES_0
, 2048);
4025 NewSummon
->SetUInt32Value(UNIT_FIELD_BYTES_1
, 0);
4026 NewSummon
->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP
, time(NULL
));
4027 NewSummon
->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE
, 0);
4028 NewSummon
->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP
, 1000);
4029 NewSummon
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
4031 NewSummon
->GetCharmInfo()->SetPetNumber(pet_number
, true);
4032 // this enables pet details window (Shift+P)
4034 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4035 NewSummon
->SetUInt32Value(UNIT_FIELD_FLAGS
,UNIT_FLAG_PVP_ATTACKABLE
);
4037 NewSummon
->InitStatsForLevel(petlevel
);
4038 NewSummon
->InitPetCreateSpells();
4040 if(NewSummon
->getPetType()==SUMMON_PET
)
4042 // Remove Demonic Sacrifice auras (new pet)
4043 Unit::AuraList
const& auraClassScripts
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
4044 for(Unit::AuraList::const_iterator itr
= auraClassScripts
.begin();itr
!=auraClassScripts
.end();)
4046 if((*itr
)->GetModifier()->m_miscvalue
==2228)
4048 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
4049 itr
= auraClassScripts
.begin();
4055 // generate new name for summon pet
4056 std::string new_name
=objmgr
.GeneratePetName(petentry
);
4057 if(!new_name
.empty())
4058 NewSummon
->SetName(new_name
);
4060 else if(NewSummon
->getPetType()==HUNTER_PET
)
4061 NewSummon
->SetByteValue(UNIT_FIELD_BYTES_2
, 2, UNIT_RENAME_NOT_ALLOWED
);
4063 NewSummon
->AIM_Initialize();
4064 NewSummon
->SetHealth(NewSummon
->GetMaxHealth());
4065 NewSummon
->SetPower(POWER_MANA
, NewSummon
->GetMaxPower(POWER_MANA
));
4067 map
->Add((Creature
*)NewSummon
);
4069 m_caster
->SetPet(NewSummon
);
4070 sLog
.outDebug("New Pet has guid %u", NewSummon
->GetGUIDLow());
4072 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4074 NewSummon
->SavePetToDB(PET_SAVE_AS_CURRENT
);
4075 ((Player
*)m_caster
)->PetSpellInitialize();
4079 void Spell::EffectLearnPetSpell(uint32 i
)
4081 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
4084 Player
*_player
= (Player
*)m_caster
;
4086 Pet
*pet
= _player
->GetPet();
4092 SpellEntry
const *learn_spellproto
= sSpellStore
.LookupEntry(m_spellInfo
->EffectTriggerSpell
[i
]);
4093 if(!learn_spellproto
)
4096 pet
->SetTP(pet
->m_TrainingPoints
- pet
->GetTPForSpell(learn_spellproto
->Id
));
4097 pet
->learnSpell(learn_spellproto
->Id
);
4099 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
4100 _player
->PetSpellInitialize();
4103 void Spell::EffectTaunt(uint32
/*i*/)
4105 // this effect use before aura Taunt apply for prevent taunt already attacking target
4106 // for spell as marked "non effective at already attacking target"
4107 if(unitTarget
&& unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4109 if(unitTarget
->getVictim()==m_caster
)
4111 SendCastResult(SPELL_FAILED_DONT_REPORT
);
4116 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4117 if(unitTarget
->CanHaveThreatList() && unitTarget
->getThreatManager().getCurrentVictim())
4118 unitTarget
->getThreatManager().addThreat(m_caster
,unitTarget
->getThreatManager().getCurrentVictim()->getThreat());
4121 void Spell::EffectWeaponDmg(uint32 i
)
4125 if(!unitTarget
->isAlive())
4128 // multiple weapon dmg effect workaround
4129 // execute only the last weapon damage
4130 // and handle all effects at once
4131 for (int j
= 0; j
< 3; j
++)
4133 switch(m_spellInfo
->Effect
[j
])
4135 case SPELL_EFFECT_WEAPON_DAMAGE
:
4136 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
:
4137 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG
:
4138 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
:
4139 if (j
< i
) // we must calculate only at last weapon effect
4145 // some spell specific modifiers
4146 bool customBonusDamagePercentMod
= false;
4147 float bonusDamagePercentMod
= 1.0f
; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4148 float weaponDamagePercentMod
= 1.0f
; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4149 float totalDamagePercentMod
= 1.0f
; // applied to final bonus+weapon damage
4150 bool normalized
= false;
4152 int32 spell_bonus
= 0; // bonus specific for spell
4153 switch(m_spellInfo
->SpellFamilyName
)
4155 case SPELLFAMILY_WARRIOR
:
4157 // Whirlwind, single only spell with 2 weapon white damage apply if have
4158 if(m_caster
->GetTypeId()==TYPEID_PLAYER
&& (m_spellInfo
->SpellFamilyFlags
& 0x00000400000000LL
))
4160 if(((Player
*)m_caster
)->GetWeaponForAttack(OFF_ATTACK
,true))
4161 spell_bonus
+= m_caster
->CalculateDamage (OFF_ATTACK
, normalized
);
4163 // Devastate bonus and sunder armor refresh
4164 else if(m_spellInfo
->SpellVisual
== 671 && m_spellInfo
->SpellIconID
== 1508)
4166 customBonusDamagePercentMod
= true;
4167 bonusDamagePercentMod
= 0.0f
; // only applied if auras found
4169 Unit::AuraList
const& list
= unitTarget
->GetAurasByType(SPELL_AURA_MOD_RESISTANCE
);
4170 for(Unit::AuraList::const_iterator itr
=list
.begin();itr
!=list
.end();++itr
)
4172 SpellEntry
const *proto
= (*itr
)->GetSpellProto();
4173 if(proto
->SpellVisual
== 406 && proto
->SpellIconID
== 565)
4175 int32 duration
= GetSpellDuration(proto
);
4176 (*itr
)->SetAuraDuration(duration
);
4177 (*itr
)->UpdateAuraDuration();
4178 bonusDamagePercentMod
+= 1.0f
; // +100%
4184 case SPELLFAMILY_ROGUE
:
4187 if(m_spellInfo
->SpellFamilyFlags
& 0x00000200LL
)
4189 customBonusDamagePercentMod
= true;
4190 bonusDamagePercentMod
= 2.5f
; // 250%
4192 // Mutilate (for each hand)
4193 else if(m_spellInfo
->SpellFamilyFlags
& 0x600000000LL
)
4197 if(unitTarget
->HasAuraState(AURA_STATE_DEADLY_POISON
))
4202 Unit::AuraMap
const& auras
= unitTarget
->GetAuras();
4203 for(Unit::AuraMap::const_iterator itr
= auras
.begin(); itr
!=auras
.end(); ++itr
)
4205 if(itr
->second
->GetSpellProto()->Dispel
== DISPEL_POISON
)
4214 totalDamagePercentMod
*= 1.5f
; // 150% if poisoned
4218 case SPELLFAMILY_PALADIN
:
4220 // Seal of Command - receive benefit from Spell Damage and Healing
4221 if(m_spellInfo
->SpellFamilyFlags
& 0x00000002000000LL
)
4223 spell_bonus
+= int32(0.20f
*m_caster
->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo
)));
4224 spell_bonus
+= int32(0.29f
*m_caster
->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo
), unitTarget
));
4228 case SPELLFAMILY_SHAMAN
:
4230 // Skyshatter Harness item set bonus
4232 if(m_spellInfo
->SpellFamilyFlags
& 0x001000000000LL
)
4234 Unit::AuraList
const& m_OverrideClassScript
= m_caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
4235 for(Unit::AuraList::const_iterator i
= m_OverrideClassScript
.begin(); i
!= m_OverrideClassScript
.end(); ++i
)
4237 // Stormstrike AP Buff
4238 if ( (*i
)->GetModifier()->m_miscvalue
== 5634 )
4240 m_caster
->CastSpell(m_caster
,38430,true,NULL
,*i
);
4248 int32 fixed_bonus
= 0;
4249 for (int j
= 0; j
< 3; j
++)
4251 switch(m_spellInfo
->Effect
[j
])
4253 case SPELL_EFFECT_WEAPON_DAMAGE
:
4254 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
:
4255 fixed_bonus
+= CalculateDamage(j
,unitTarget
);
4257 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG
:
4258 fixed_bonus
+= CalculateDamage(j
,unitTarget
);
4261 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
:
4262 weaponDamagePercentMod
*= float(CalculateDamage(j
,unitTarget
)) / 100.0f
;
4264 // applied only to prev.effects fixed damage
4265 if(customBonusDamagePercentMod
)
4266 fixed_bonus
= int32(fixed_bonus
*bonusDamagePercentMod
);
4268 fixed_bonus
= int32(fixed_bonus
*weaponDamagePercentMod
);
4271 break; // not weapon damage effect, just skip
4275 // non-weapon damage
4276 int32 bonus
= spell_bonus
+ fixed_bonus
;
4278 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4282 switch(m_attackType
)
4285 case BASE_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_MAINHAND
; break;
4286 case OFF_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_OFFHAND
; break;
4287 case RANGED_ATTACK
: unitMod
= UNIT_MOD_DAMAGE_RANGED
; break;
4290 float weapon_total_pct
= m_caster
->GetModifierValue(unitMod
, TOTAL_PCT
);
4291 bonus
= int32(bonus
*weapon_total_pct
);
4294 // + weapon damage with applied weapon% dmg to base weapon damage in call
4295 bonus
+= int32(m_caster
->CalculateDamage(m_attackType
, normalized
)*weaponDamagePercentMod
);
4298 bonus
= int32(bonus
*totalDamagePercentMod
);
4300 // prevent negative damage
4301 uint32 eff_damage
= uint32(bonus
> 0 ? bonus
: 0);
4303 // Add melee damage bonuses (also check for negative)
4304 m_caster
->MeleeDamageBonus(unitTarget
, &eff_damage
, m_attackType
, m_spellInfo
);
4305 m_damage
+= eff_damage
;
4308 if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (m_spellInfo
->SpellFamilyFlags
& 0x2000000))
4310 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
4311 ((Player
*)m_caster
)->AddComboPoints(unitTarget
, 1);
4315 if(m_spellInfo
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (m_spellInfo
->SpellFamilyFlags
==0x0000040000000000LL
))
4317 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
4318 ((Player
*)m_caster
)->AddComboPoints(unitTarget
,1);
4322 if(m_attackType
== RANGED_ATTACK
&& m_caster
->GetTypeId() == TYPEID_PLAYER
)
4324 Item
*pItem
= ((Player
*)m_caster
)->GetWeaponForAttack( RANGED_ATTACK
);
4326 // wands don't have ammo
4327 if(!pItem
|| pItem
->IsBroken() || pItem
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_WAND
)
4330 if( pItem
->GetProto()->InventoryType
== INVTYPE_THROWN
)
4332 if(pItem
->GetMaxStackCount()==1)
4334 // decrease durability for non-stackable throw weapon
4335 ((Player
*)m_caster
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED
);
4339 // decrease items amount for stackable throw weapon
4341 ((Player
*)m_caster
)->DestroyItemCount( pItem
, count
, true);
4344 else if(uint32 ammo
= ((Player
*)m_caster
)->GetUInt32Value(PLAYER_AMMO_ID
))
4345 ((Player
*)m_caster
)->DestroyItemCount(ammo
, 1, true);
4349 void Spell::EffectThreat(uint32
/*i*/)
4351 if(!unitTarget
|| !unitTarget
->isAlive() || !m_caster
->isAlive())
4354 if(!unitTarget
->CanHaveThreatList())
4357 unitTarget
->AddThreat(m_caster
, float(damage
));
4360 void Spell::EffectHealMaxHealth(uint32
/*i*/)
4364 if(!unitTarget
->isAlive())
4367 uint32 heal
= m_caster
->GetMaxHealth();
4372 void Spell::EffectInterruptCast(uint32
/*i*/)
4376 if(!unitTarget
->isAlive())
4379 // TODO: not all spells that used this effect apply cooldown at school spells
4380 // also exist case: apply cooldown to interrupted cast only and to all spells
4381 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
4383 if (unitTarget
->m_currentSpells
[i
])
4385 // check if we can interrupt spell
4386 if ( unitTarget
->m_currentSpells
[i
]->m_spellInfo
->InterruptFlags
& SPELL_INTERRUPT_FLAG_INTERRUPT
&& unitTarget
->m_currentSpells
[i
]->m_spellInfo
->PreventionType
== SPELL_PREVENTION_TYPE_SILENCE
)
4388 unitTarget
->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget
->m_currentSpells
[i
]->m_spellInfo
), GetSpellDuration(m_spellInfo
));
4389 unitTarget
->InterruptSpell(i
,false);
4395 void Spell::EffectSummonObjectWild(uint32 i
)
4397 uint32 gameobject_id
= m_spellInfo
->EffectMiscValue
[i
];
4399 GameObject
* pGameObj
= new GameObject
;
4401 WorldObject
* target
= focusObject
;
4406 if(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
4408 x
= m_targets
.m_destX
;
4409 y
= m_targets
.m_destY
;
4410 z
= m_targets
.m_destZ
;
4413 m_caster
->GetClosePoint(x
,y
,z
,DEFAULT_WORLD_OBJECT_SIZE
);
4415 Map
*map
= target
->GetMap();
4417 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), gameobject_id
, map
,
4418 x
, y
, z
, target
->GetOrientation(), 0, 0, 0, 0, 100, 1))
4424 int32 duration
= GetSpellDuration(m_spellInfo
);
4425 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4426 pGameObj
->SetSpellId(m_spellInfo
->Id
);
4428 if(pGameObj
->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP
) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4429 m_caster
->AddGameObject(pGameObj
);
4432 if(pGameObj
->GetMapId() == 489 && pGameObj
->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP
) //WS
4434 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4436 Player
*pl
= (Player
*)m_caster
;
4437 BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround();
4438 if(bg
&& bg
->GetTypeID()==BATTLEGROUND_WS
&& bg
->GetStatus() == STATUS_IN_PROGRESS
)
4440 uint32 team
= ALLIANCE
;
4442 if(pl
->GetTeam() == team
)
4445 ((BattleGroundWS
*)bg
)->SetDroppedFlagGUID(pGameObj
->GetGUID(),team
);
4450 if(pGameObj
->GetMapId() == 566 && pGameObj
->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP
) //EY
4452 if(m_caster
->GetTypeId() == TYPEID_PLAYER
)
4454 BattleGround
* bg
= ((Player
*)m_caster
)->GetBattleGround();
4455 if(bg
&& bg
->GetTypeID()==BATTLEGROUND_EY
&& bg
->GetStatus() == STATUS_IN_PROGRESS
)
4457 ((BattleGroundEY
*)bg
)->SetDroppedFlagGUID(pGameObj
->GetGUID());
4462 if(uint32 linkedEntry
= pGameObj
->GetLinkedGameObjectEntry())
4464 GameObject
* linkedGO
= new GameObject
;
4465 if(linkedGO
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), linkedEntry
, map
,
4466 x
, y
, z
, target
->GetOrientation(), 0, 0, 0, 0, 100, 1))
4468 linkedGO
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4469 linkedGO
->SetSpellId(m_spellInfo
->Id
);
4471 m_caster
->AddGameObject(linkedGO
);
4483 void Spell::EffectScriptEffect(uint32 effIndex
)
4485 // TODO: we must implement hunter pet summon at login there (spell 6962)
4488 switch(m_spellInfo
->Id
)
4490 // PX-238 Winter Wondervolt TRAP
4493 if( unitTarget
->HasAura(26272,0)
4494 || unitTarget
->HasAura(26157,0)
4495 || unitTarget
->HasAura(26273,0)
4496 || unitTarget
->HasAura(26274,0))
4504 iTmpSpellId
= 26272;
4507 iTmpSpellId
= 26157;
4510 iTmpSpellId
= 26273;
4513 iTmpSpellId
= 26274;
4517 unitTarget
->CastSpell(unitTarget
, iTmpSpellId
, true);
4525 if(!itemTarget
&& m_caster
->GetTypeId()!=TYPEID_PLAYER
)
4528 uint32 spell_id
= 0;
4531 case 1: spell_id
= 8854; break;
4532 default: spell_id
= 8855; break;
4535 m_caster
->CastSpell(m_caster
,spell_id
,true,NULL
);
4539 // Healthstone creating spells
4549 Unit::AuraList
const& mDummyAuras
= unitTarget
->GetAurasByType(SPELL_AURA_DUMMY
);
4550 for(Unit::AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
4552 if((*i
)->GetId() == 18692)
4557 else if((*i
)->GetId() == 18693)
4564 static uint32
const itypes
[6][3] = {
4565 { 5512,19004,19005}, // Minor Healthstone
4566 { 5511,19006,19007}, // Lesser Healthstone
4567 { 5509,19008,19009}, // Healthstone
4568 { 5510,19010,19011}, // Greater Healthstone
4569 { 9421,19012,19013}, // Major Healthstone
4570 {22103,22104,22105} // Master Healthstone
4573 switch(m_spellInfo
->Id
)
4575 case 6201: itemtype
=itypes
[0][rank
];break; // Minor Healthstone
4576 case 6202: itemtype
=itypes
[1][rank
];break; // Lesser Healthstone
4577 case 5699: itemtype
=itypes
[2][rank
];break; // Healthstone
4578 case 11729: itemtype
=itypes
[3][rank
];break; // Greater Healthstone
4579 case 11730: itemtype
=itypes
[4][rank
];break; // Major Healthstone
4580 case 27230: itemtype
=itypes
[5][rank
];break; // Master Healthstone
4584 DoCreateItem( effIndex
, itemtype
);
4587 // Brittle Armor - need remove one 24575 Brittle Armor aura
4589 unitTarget
->RemoveSingleAuraFromStack(24575, 0);
4590 unitTarget
->RemoveSingleAuraFromStack(24575, 1);
4592 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4594 unitTarget
->RemoveSingleAuraFromStack(26464, 0);
4596 // Orb teleport spells
4610 switch(m_spellInfo
->Id
)
4612 case 25140: spellid
= 32571; break;
4613 case 25143: spellid
= 32572; break;
4614 case 25650: spellid
= 30140; break;
4615 case 25652: spellid
= 30141; break;
4616 case 29128: spellid
= 32568; break;
4617 case 29129: spellid
= 32569; break;
4618 case 35376: spellid
= 25649; break;
4619 case 35727: spellid
= 35730; break;
4624 unitTarget
->CastSpell(unitTarget
,spellid
,false);
4628 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4643 if(!unitTarget
|| !unitTarget
->isAlive())
4646 // Onyxia Scale Cloak
4647 if(unitTarget
->GetDummyAura(22683))
4651 m_caster
->CastSpell(unitTarget
, 22682, true);
4656 // Summon Black Qiraji Battle Tank
4662 // Prevent stacking of mounts
4663 unitTarget
->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED
);
4665 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4666 if (unitTarget
->GetAreaId() == 3428)
4667 unitTarget
->CastSpell(unitTarget
, 25863, false);
4669 unitTarget
->CastSpell(unitTarget
, 26655, false);
4672 // Piccolo of the Flaming Fire
4675 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4677 unitTarget
->HandleEmoteCommand(EMOTE_STATE_DANCE
);
4686 unitTarget
->CastSpell(unitTarget
, 28694, true);
4695 // 25% chance of casting a random buff
4696 if(roll_chance_i(75))
4699 // triggered spells are 28703 to 28707
4700 // Note: some sources say, that there was the possibility of
4701 // receiving a debuff. However, this seems to be removed by a patch.
4702 const uint32 spellid
= 28703;
4704 // don't overwrite an existing aura
4705 for(uint8 i
=0; i
<5; i
++)
4706 if(unitTarget
->HasAura(spellid
+i
, 0))
4708 unitTarget
->CastSpell(unitTarget
, spellid
+urand(0, 4), true);
4717 // 25% chance of casting Nightmare Pollen
4718 if(roll_chance_i(75))
4720 unitTarget
->CastSpell(unitTarget
, 28721, true);
4724 // Mirren's Drinking Hat
4728 switch ( urand(1,6) )
4730 case 1: case 2: case 3: item
= 23584; break;// Loch Modan Lager
4731 case 4: case 5: item
= 23585; break;// Stouthammer Lite
4732 case 6: item
= 23586; break;// Aerie Peak Pale Ale
4735 DoCreateItem(effIndex
,item
);
4741 // Removes snares and roots.
4742 uint32 mechanic_mask
= (1<<MECHANIC_ROOT
) | (1<<MECHANIC_SNARE
);
4743 Unit::AuraMap
& Auras
= unitTarget
->GetAuras();
4744 for(Unit::AuraMap::iterator iter
= Auras
.begin(), next
; iter
!= Auras
.end(); iter
= next
)
4748 Aura
*aur
= iter
->second
;
4749 if (!aur
->IsPositive()) //only remove negative spells
4751 // check for mechanic mask
4752 if(GetSpellMechanicMask(aur
->GetSpellProto(), aur
->GetEffIndex()) & mechanic_mask
)
4754 unitTarget
->RemoveAurasDueToSpell(aur
->GetId());
4758 next
= Auras
.begin();
4764 case 41126: // Flame Crash
4769 unitTarget
->CastSpell(unitTarget
, 41131, true);
4772 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4777 unitTarget
->CastSpell(unitTarget
, 44870, true);
4781 // Goblin Weather Machine
4803 unitTarget
->CastSpell(unitTarget
, spellId
, true);
4809 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4812 ((Player
*)unitTarget
)->ModifyMoney(50000000);
4818 if( m_spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
4820 switch(m_spellInfo
->SpellFamilyFlags
)
4825 if(!unitTarget
|| !unitTarget
->isAlive())
4827 uint32 spellId2
= 0;
4829 // all seals have aura dummy
4830 Unit::AuraList
const& m_dummyAuras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
4831 for(Unit::AuraList::const_iterator itr
= m_dummyAuras
.begin(); itr
!= m_dummyAuras
.end(); ++itr
)
4833 SpellEntry
const *spellInfo
= (*itr
)->GetSpellProto();
4835 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4836 if ( !spellInfo
|| !IsSealSpell((*itr
)->GetSpellProto()) || (*itr
)->GetEffIndex() != 2 )
4839 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4840 spellId2
= (*itr
)->GetSpellProto()->EffectBasePoints
[2]+1;
4845 // found, remove seal
4846 m_caster
->RemoveAurasDueToSpell((*itr
)->GetId());
4848 // Sanctified Judgement
4849 Unit::AuraList
const& m_auras
= m_caster
->GetAurasByType(SPELL_AURA_DUMMY
);
4850 for(Unit::AuraList::const_iterator i
= m_auras
.begin(); i
!= m_auras
.end(); ++i
)
4852 if ((*i
)->GetSpellProto()->SpellIconID
== 205 && (*i
)->GetSpellProto()->Attributes
== 0x01D0LL
)
4854 int32 chance
= (*i
)->GetModifier()->m_amount
;
4855 if ( roll_chance_i(chance
) )
4857 int32 mana
= spellInfo
->manaCost
;
4858 if ( Player
* modOwner
= m_caster
->GetSpellModOwner() )
4859 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_COST
, mana
);
4860 mana
= int32(mana
* 0.8f
);
4861 m_caster
->CastCustomSpell(m_caster
,31930,&mana
,NULL
,NULL
,true,NULL
,*i
);
4870 m_caster
->CastSpell(unitTarget
,spellId2
,true);
4876 // normal DB scripted effect
4880 sLog
.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo
->Id
);
4881 sWorld
.ScriptsStart(sSpellScripts
, m_spellInfo
->Id
, m_caster
, unitTarget
);
4884 void Spell::EffectSanctuary(uint32
/*i*/)
4888 //unitTarget->CombatStop();
4890 unitTarget
->CombatStop();
4891 unitTarget
->getHostilRefManager().deleteReferences(); // stop all fighting
4892 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4893 if(m_spellInfo
->SpellFamilyName
== SPELLFAMILY_ROGUE
&& (m_spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE_VANISH
))
4895 ((Player
*)m_caster
)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT
);
4899 void Spell::EffectAddComboPoints(uint32
/*i*/)
4904 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
4910 ((Player
*)m_caster
)->AddComboPoints(unitTarget
, damage
);
4913 void Spell::EffectDuel(uint32 i
)
4915 if(!m_caster
|| !unitTarget
|| m_caster
->GetTypeId() != TYPEID_PLAYER
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
4918 Player
*caster
= (Player
*)m_caster
;
4919 Player
*target
= (Player
*)unitTarget
;
4921 // caster or target already have requested duel
4922 if( caster
->duel
|| target
->duel
|| !target
->GetSocial() || target
->GetSocial()->HasIgnore(caster
->GetGUIDLow()) )
4925 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4926 // Don't have to check the target's map since you cannot challenge someone across maps
4927 if( caster
->GetMapId() != 0 && caster
->GetMapId() != 1 && caster
->GetMapId() != 530)
4929 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4933 AreaTableEntry
const* casterAreaEntry
= GetAreaEntryByAreaID(caster
->GetZoneId());
4934 if(casterAreaEntry
&& (casterAreaEntry
->flags
& AREA_FLAG_CAPITAL
) )
4936 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4940 AreaTableEntry
const* targetAreaEntry
= GetAreaEntryByAreaID(target
->GetZoneId());
4941 if(targetAreaEntry
&& (targetAreaEntry
->flags
& AREA_FLAG_CAPITAL
) )
4943 SendCastResult(SPELL_FAILED_NO_DUELING
); // Dueling isn't allowed here
4947 //CREATE DUEL FLAG OBJECT
4948 GameObject
* pGameObj
= new GameObject
;
4950 uint32 gameobject_id
= m_spellInfo
->EffectMiscValue
[i
];
4952 Map
*map
= m_caster
->GetMap();
4953 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), gameobject_id
, map
,
4954 m_caster
->GetPositionX()+(unitTarget
->GetPositionX()-m_caster
->GetPositionX())/2 ,
4955 m_caster
->GetPositionY()+(unitTarget
->GetPositionY()-m_caster
->GetPositionY())/2 ,
4956 m_caster
->GetPositionZ(),
4957 m_caster
->GetOrientation(), 0, 0, 0, 0, 0, 1))
4963 pGameObj
->SetUInt32Value(GAMEOBJECT_FACTION
, m_caster
->getFaction() );
4964 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel()+1 );
4965 int32 duration
= GetSpellDuration(m_spellInfo
);
4966 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
4967 pGameObj
->SetSpellId(m_spellInfo
->Id
);
4969 m_caster
->AddGameObject(pGameObj
);
4974 WorldPacket
data(SMSG_DUEL_REQUESTED
, 16);
4975 data
<< pGameObj
->GetGUID();
4976 data
<< caster
->GetGUID();
4977 caster
->GetSession()->SendPacket(&data
);
4978 target
->GetSession()->SendPacket(&data
);
4981 DuelInfo
*duel
= new DuelInfo
;
4982 duel
->initiator
= caster
;
4983 duel
->opponent
= target
;
4984 duel
->startTime
= 0;
4985 duel
->startTimer
= 0;
4986 caster
->duel
= duel
;
4988 DuelInfo
*duel2
= new DuelInfo
;
4989 duel2
->initiator
= caster
;
4990 duel2
->opponent
= caster
;
4991 duel2
->startTime
= 0;
4992 duel2
->startTimer
= 0;
4993 target
->duel
= duel2
;
4995 caster
->SetUInt64Value(PLAYER_DUEL_ARBITER
,pGameObj
->GetGUID());
4996 target
->SetUInt64Value(PLAYER_DUEL_ARBITER
,pGameObj
->GetGUID());
4999 void Spell::EffectStuck(uint32
/*i*/)
5001 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5004 if(!sWorld
.getConfig(CONFIG_CAST_UNSTUCK
))
5007 Player
* pTarget
= (Player
*)unitTarget
;
5009 sLog
.outDebug("Spell Effect: Stuck");
5010 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());
5012 if(pTarget
->isInFlight())
5015 // homebind location is loaded always
5016 pTarget
->TeleportTo(pTarget
->m_homebindMapId
,pTarget
->m_homebindX
,pTarget
->m_homebindY
,pTarget
->m_homebindZ
,pTarget
->GetOrientation(), (unitTarget
==m_caster
? TELE_TO_SPELL
: 0));
5018 // Stuck spell trigger Hearthstone cooldown
5019 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(8690);
5022 Spell
spell(pTarget
,spellInfo
,true,0);
5023 spell
.SendSpellCooldown();
5026 void Spell::EffectSummonPlayer(uint32
/*i*/)
5028 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5031 // Evil Twin (ignore player summon, but hide this for summoner)
5032 if(unitTarget
->GetDummyAura(23445))
5036 m_caster
->GetClosePoint(x
,y
,z
,unitTarget
->GetObjectSize());
5038 ((Player
*)unitTarget
)->SetSummonPoint(m_caster
->GetMapId(),x
,y
,z
);
5040 WorldPacket
data(SMSG_SUMMON_REQUEST
, 8+4+4);
5041 data
<< uint64(m_caster
->GetGUID()); // summoner guid
5042 data
<< uint32(m_caster
->GetZoneId()); // summoner zone
5043 data
<< uint32(MAX_PLAYER_SUMMON_DELAY
*1000); // auto decline after msecs
5044 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5047 static ScriptInfo
generateActivateCommand()
5050 si
.command
= SCRIPT_COMMAND_ACTIVATE_OBJECT
;
5054 void Spell::EffectActivateObject(uint32 effect_idx
)
5059 static ScriptInfo activateCommand
= generateActivateCommand();
5061 int32 delay_secs
= m_spellInfo
->EffectMiscValue
[effect_idx
];
5063 sWorld
.ScriptCommandStart(activateCommand
, delay_secs
, m_caster
, gameObjTarget
);
5066 void Spell::EffectSummonTotem(uint32 i
)
5069 switch(m_spellInfo
->EffectMiscValueB
[i
])
5071 case SUMMON_TYPE_TOTEM_SLOT1
: slot
= 0; break;
5072 case SUMMON_TYPE_TOTEM_SLOT2
: slot
= 1; break;
5073 case SUMMON_TYPE_TOTEM_SLOT3
: slot
= 2; break;
5074 case SUMMON_TYPE_TOTEM_SLOT4
: slot
= 3; break;
5075 // Battle standard case
5076 case SUMMON_TYPE_TOTEM
: slot
= 254; break;
5077 // jewelery statue case, like totem without slot
5078 case SUMMON_TYPE_GUARDIAN
: slot
= 255; break;
5082 if(slot
< MAX_TOTEM
)
5084 uint64 guid
= m_caster
->m_TotemSlot
[slot
];
5087 Creature
*OldTotem
= ObjectAccessor::GetCreature(*m_caster
, guid
);
5088 if(OldTotem
&& OldTotem
->isTotem())
5089 ((Totem
*)OldTotem
)->UnSummon();
5094 if (m_caster
->GetTypeId()==TYPEID_PLAYER
)
5095 team
= ((Player
*)m_caster
)->GetTeam();
5097 Totem
* pTotem
= new Totem
;
5099 if(!pTotem
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), m_caster
->GetMap(), m_spellInfo
->EffectMiscValue
[i
], team
))
5105 float angle
= slot
< MAX_TOTEM
? M_PI
/MAX_TOTEM
- (slot
*2*M_PI
/MAX_TOTEM
) : 0;
5108 m_caster
->GetClosePoint(x
,y
,z
,pTotem
->GetObjectSize(),2.0f
,angle
);
5110 // totem must be at same Z in case swimming caster and etc.
5111 if( fabs( z
- m_caster
->GetPositionZ() ) > 5 )
5112 z
= m_caster
->GetPositionZ();
5114 pTotem
->Relocate(x
, y
, z
, m_caster
->GetOrientation());
5116 if(slot
< MAX_TOTEM
)
5117 m_caster
->m_TotemSlot
[slot
] = pTotem
->GetGUID();
5119 pTotem
->SetOwner(m_caster
->GetGUID());
5120 pTotem
->SetTypeBySummonSpell(m_spellInfo
); // must be after Create call where m_spells initilized
5122 int32 duration
=GetSpellDuration(m_spellInfo
);
5123 if(Player
* modOwner
= m_caster
->GetSpellModOwner())
5124 modOwner
->ApplySpellMod(m_spellInfo
->Id
,SPELLMOD_DURATION
, duration
);
5125 pTotem
->SetDuration(duration
);
5127 if (damage
) // if not spell info, DB values used
5129 pTotem
->SetMaxHealth(damage
);
5130 pTotem
->SetHealth(damage
);
5133 pTotem
->SetUInt32Value(UNIT_CREATED_BY_SPELL
,m_spellInfo
->Id
);
5134 pTotem
->SetFlag(UNIT_FIELD_FLAGS
,UNIT_FLAG_PVP_ATTACKABLE
);
5136 pTotem
->ApplySpellImmune(m_spellInfo
->Id
,IMMUNITY_STATE
,SPELL_AURA_MOD_FEAR
,true);
5137 pTotem
->ApplySpellImmune(m_spellInfo
->Id
,IMMUNITY_STATE
,SPELL_AURA_TRANSFORM
,true);
5139 pTotem
->Summon(m_caster
);
5141 if(slot
< MAX_TOTEM
&& m_caster
->GetTypeId() == TYPEID_PLAYER
)
5143 WorldPacket
data(SMSG_TOTEM_CREATED
, 1+8+4+4);
5144 data
<< uint8(slot
);
5145 data
<< uint64(pTotem
->GetGUID());
5146 data
<< uint32(duration
);
5147 data
<< uint32(m_spellInfo
->Id
);
5148 ((Player
*)m_caster
)->SendDirectMessage(&data
);
5152 void Spell::EffectEnchantHeldItem(uint32 i
)
5154 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5155 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5158 Player
* item_owner
= (Player
*)unitTarget
;
5159 Item
* item
= item_owner
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5165 if(!item
->IsEquipped())
5168 if (m_spellInfo
->EffectMiscValue
[i
])
5170 uint32 enchant_id
= m_spellInfo
->EffectMiscValue
[i
];
5171 int32 duration
= GetSpellDuration(m_spellInfo
); //Try duration index first ..
5173 duration
= m_currentBasePoints
[i
]+1; //Base points after ..
5175 duration
= 10; //10 seconds for enchants which don't have listed duration
5177 SpellItemEnchantmentEntry
const *pEnchant
= sSpellItemEnchantmentStore
.LookupEntry(enchant_id
);
5181 // Always go to temp enchantment slot
5182 EnchantmentSlot slot
= TEMP_ENCHANTMENT_SLOT
;
5184 // Enchantment will not be applied if a different one already exists
5185 if(item
->GetEnchantmentId(slot
) && item
->GetEnchantmentId(slot
) != enchant_id
)
5188 // Apply the temporary enchantment
5189 item
->SetEnchantment(slot
, enchant_id
, duration
*1000, 0);
5190 item_owner
->ApplyEnchantment(item
,slot
,true);
5194 void Spell::EffectDisEnchant(uint32
/*i*/)
5196 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5199 Player
* p_caster
= (Player
*)m_caster
;
5200 if(!itemTarget
|| !itemTarget
->GetProto()->DisenchantID
)
5203 p_caster
->UpdateCraftSkill(m_spellInfo
->Id
);
5205 ((Player
*)m_caster
)->SendLoot(itemTarget
->GetGUID(),LOOT_DISENCHANTING
);
5207 // item will be removed at disenchanting end
5210 void Spell::EffectInebriate(uint32
/*i*/)
5212 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5215 Player
*player
= (Player
*)unitTarget
;
5216 uint16 currentDrunk
= player
->GetDrunkValue();
5217 uint16 drunkMod
= damage
* 256;
5218 if (currentDrunk
+ drunkMod
> 0xFFFF)
5219 currentDrunk
= 0xFFFF;
5221 currentDrunk
+= drunkMod
;
5222 player
->SetDrunkValue(currentDrunk
, m_CastItem
?m_CastItem
->GetEntry():0);
5225 void Spell::EffectFeedPet(uint32 i
)
5227 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5230 Player
*_player
= (Player
*)m_caster
;
5235 Pet
*pet
= _player
->GetPet();
5242 int32 benefit
= pet
->GetCurrentFoodBenefitLevel(itemTarget
->GetProto()->ItemLevel
);
5247 _player
->DestroyItemCount(itemTarget
,count
,true);
5248 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5250 m_caster
->CastCustomSpell(m_caster
,m_spellInfo
->EffectTriggerSpell
[i
],&benefit
,NULL
,NULL
,true);
5253 void Spell::EffectDismissPet(uint32
/*i*/)
5255 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5258 Pet
* pet
= m_caster
->GetPet();
5260 // not let dismiss dead pet
5261 if(!pet
||!pet
->isAlive())
5264 ((Player
*)m_caster
)->RemovePet(pet
,PET_SAVE_NOT_IN_SLOT
);
5267 void Spell::EffectSummonObject(uint32 i
)
5269 uint32 go_id
= m_spellInfo
->EffectMiscValue
[i
];
5272 switch(m_spellInfo
->Effect
[i
])
5274 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1
: slot
= 0; break;
5275 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2
: slot
= 1; break;
5276 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3
: slot
= 2; break;
5277 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4
: slot
= 3; break;
5281 uint64 guid
= m_caster
->m_ObjectSlot
[slot
];
5284 GameObject
* obj
= NULL
;
5286 obj
= ObjectAccessor::GetGameObject(*m_caster
, guid
);
5288 if(obj
) obj
->Delete();
5289 m_caster
->m_ObjectSlot
[slot
] = 0;
5292 GameObject
* pGameObj
= new GameObject
;
5294 float rot2
= sin(m_caster
->GetOrientation()/2);
5295 float rot3
= cos(m_caster
->GetOrientation()/2);
5298 // If dest location if present
5299 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5301 x
= m_targets
.m_destX
;
5302 y
= m_targets
.m_destY
;
5303 z
= m_targets
.m_destZ
;
5305 // Summon in random point all other units if location present
5307 m_caster
->GetClosePoint(x
,y
,z
,DEFAULT_WORLD_OBJECT_SIZE
);
5309 Map
*map
= m_caster
->GetMap();
5310 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), go_id
, map
, x
, y
, z
, m_caster
->GetOrientation(), 0, 0, rot2
, rot3
, 0, 1))
5316 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
,m_caster
->getLevel());
5317 int32 duration
= GetSpellDuration(m_spellInfo
);
5318 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
5319 pGameObj
->SetSpellId(m_spellInfo
->Id
);
5320 m_caster
->AddGameObject(pGameObj
);
5323 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
5324 data
<< pGameObj
->GetGUID();
5325 m_caster
->SendMessageToSet(&data
,true);
5327 m_caster
->m_ObjectSlot
[slot
] = pGameObj
->GetGUID();
5330 void Spell::EffectResurrect(uint32
/*effIndex*/)
5334 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5337 if(unitTarget
->isAlive())
5339 if(!unitTarget
->IsInWorld())
5342 switch (m_spellInfo
->Id
)
5344 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5346 if (roll_chance_i(67))
5348 m_caster
->CastSpell(m_caster
, 8338, true, m_CastItem
);
5352 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5354 if (roll_chance_i(50))
5356 m_caster
->CastSpell(m_caster
, 23055, true, m_CastItem
);
5364 Player
* pTarget
= ((Player
*)unitTarget
);
5366 if(pTarget
->isRessurectRequested()) // already have one active request
5369 uint32 health
= pTarget
->GetMaxHealth() * damage
/ 100;
5370 uint32 mana
= pTarget
->GetMaxPower(POWER_MANA
) * damage
/ 100;
5372 pTarget
->setResurrectRequestData(m_caster
->GetGUID(), m_caster
->GetMapId(), m_caster
->GetPositionX(), m_caster
->GetPositionY(), m_caster
->GetPositionZ(), health
, mana
);
5373 SendResurrectRequest(pTarget
);
5376 void Spell::EffectAddExtraAttacks(uint32
/*i*/)
5378 if(!unitTarget
|| !unitTarget
->isAlive())
5381 if( unitTarget
->m_extraAttacks
)
5384 unitTarget
->m_extraAttacks
= damage
;
5387 void Spell::EffectParry(uint32
/*i*/)
5389 if (unitTarget
->GetTypeId() == TYPEID_PLAYER
)
5391 ((Player
*)unitTarget
)->SetCanParry(true);
5395 void Spell::EffectBlock(uint32
/*i*/)
5397 if (unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5400 ((Player
*)unitTarget
)->SetCanBlock(true);
5403 void Spell::EffectMomentMove(uint32 i
)
5405 if(unitTarget
->isInFlight())
5408 if( m_spellInfo
->rangeIndex
== 1) //self range
5410 uint32 mapid
= m_caster
->GetMapId();
5411 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[i
]));
5415 unitTarget
->GetClosePoint(fx
,fy
,fz
,unitTarget
->GetObjectSize(),dis
);
5417 unitTarget
->GetPosition(ox
,oy
,oz
);
5419 float fx2
,fy2
,fz2
; // getObjectHitPos overwrite last args in any result case
5420 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid
, ox
,oy
,oz
+0.5, fx
,fy
,oz
+0.5,fx2
,fy2
,fz2
, -0.5))
5425 unitTarget
->UpdateGroundPositionZ(fx
,fy
,fz
);
5428 if(unitTarget
->GetTypeId() == TYPEID_PLAYER
)
5429 ((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));
5431 m_caster
->GetMap()->CreatureRelocation((Creature
*)unitTarget
, fx
, fy
, fz
, unitTarget
->GetOrientation());
5435 void Spell::EffectReputation(uint32 i
)
5437 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5440 Player
*_player
= (Player
*)unitTarget
;
5442 int32 rep_change
= m_currentBasePoints
[i
]+1; // field store reputation change -1
5444 uint32 faction_id
= m_spellInfo
->EffectMiscValue
[i
];
5446 FactionEntry
const* factionEntry
= sFactionStore
.LookupEntry(faction_id
);
5451 _player
->ModifyFactionReputation(factionEntry
,rep_change
);
5454 void Spell::EffectQuestComplete(uint32 i
)
5456 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5459 Player
*_player
= (Player
*)m_caster
;
5461 uint32 quest_id
= m_spellInfo
->EffectMiscValue
[i
];
5462 _player
->AreaExploredOrEventHappens(quest_id
);
5465 void Spell::EffectSelfResurrect(uint32 i
)
5467 if(!unitTarget
|| unitTarget
->isAlive())
5469 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5471 if(!unitTarget
->IsInWorld())
5480 health
= uint32(-damage
);
5481 mana
= m_spellInfo
->EffectMiscValue
[i
];
5486 health
= uint32(damage
/100.0f
*unitTarget
->GetMaxHealth());
5487 if(unitTarget
->GetMaxPower(POWER_MANA
) > 0)
5488 mana
= uint32(damage
/100.0f
*unitTarget
->GetMaxPower(POWER_MANA
));
5491 Player
*plr
= ((Player
*)unitTarget
);
5492 plr
->ResurrectPlayer(0.0f
);
5494 plr
->SetHealth( health
);
5495 plr
->SetPower(POWER_MANA
, mana
);
5496 plr
->SetPower(POWER_RAGE
, 0 );
5497 plr
->SetPower(POWER_ENERGY
, plr
->GetMaxPower(POWER_ENERGY
) );
5499 plr
->SpawnCorpseBones();
5504 void Spell::EffectSkinning(uint32
/*i*/)
5506 if(unitTarget
->GetTypeId() != TYPEID_UNIT
)
5508 if(!m_caster
|| m_caster
->GetTypeId() != TYPEID_PLAYER
)
5511 Creature
* creature
= (Creature
*) unitTarget
;
5512 int32 targetLevel
= creature
->getLevel();
5514 uint32 skill
= creature
->GetCreatureInfo()->GetRequiredLootSkill();
5516 ((Player
*)m_caster
)->SendLoot(creature
->GetGUID(),LOOT_SKINNING
);
5517 creature
->RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
5519 int32 reqValue
= targetLevel
< 10 ? 0 : targetLevel
< 20 ? (targetLevel
-10)*10 : targetLevel
*5;
5521 int32 skillValue
= ((Player
*)m_caster
)->GetPureSkillValue(skill
);
5523 // Double chances for elites
5524 ((Player
*)m_caster
)->UpdateGatherSkill(skill
, skillValue
, reqValue
, creature
->isElite() ? 2 : 1 );
5527 void Spell::EffectCharge(uint32
/*i*/)
5529 if(!unitTarget
|| !m_caster
)
5533 unitTarget
->GetContactPoint(m_caster
, x
, y
, z
);
5534 if(unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5535 ((Creature
*)unitTarget
)->StopMoving();
5537 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5538 m_caster
->SendMonsterMove(x
, y
, z
, 0, MOVEMENTFLAG_WALK_MODE
, 1);
5540 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5541 m_caster
->GetMap()->CreatureRelocation((Creature
*)m_caster
,x
,y
,z
,m_caster
->GetOrientation());
5543 // not all charge effects used in negative spells
5544 if ( !IsPositiveSpell(m_spellInfo
->Id
))
5545 m_caster
->Attack(unitTarget
,true);
5548 void Spell::EffectSummonCritter(uint32 i
)
5550 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5552 Player
* player
= (Player
*)m_caster
;
5554 uint32 pet_entry
= m_spellInfo
->EffectMiscValue
[i
];
5558 Pet
* old_critter
= player
->GetMiniPet();
5560 // for same pet just despawn
5561 if(old_critter
&& old_critter
->GetEntry() == pet_entry
)
5563 player
->RemoveMiniPet();
5567 // despawn old pet before summon new
5569 player
->RemoveMiniPet();
5572 Pet
* critter
= new Pet(MINI_PET
);
5574 Map
*map
= m_caster
->GetMap();
5575 uint32 pet_number
= objmgr
.GeneratePetNumber();
5576 if(!critter
->Create(objmgr
.GenerateLowGuid(HIGHGUID_PET
),
5577 map
, pet_entry
, pet_number
))
5579 sLog
.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo
->Id
, pet_entry
);
5585 // If dest location if present
5586 if (m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5588 x
= m_targets
.m_destX
;
5589 y
= m_targets
.m_destY
;
5590 z
= m_targets
.m_destZ
;
5592 // Summon if dest location not present near caster
5594 m_caster
->GetClosePoint(x
,y
,z
,critter
->GetObjectSize());
5596 critter
->Relocate(x
,y
,z
,m_caster
->GetOrientation());
5598 if(!critter
->IsPositionValid())
5600 sLog
.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5601 critter
->GetGUIDLow(), critter
->GetEntry(), critter
->GetPositionX(), critter
->GetPositionY());
5606 critter
->SetOwnerGUID(m_caster
->GetGUID());
5607 critter
->SetCreatorGUID(m_caster
->GetGUID());
5608 critter
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,m_caster
->getFaction());
5609 critter
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, m_spellInfo
->Id
);
5611 critter
->AIM_Initialize();
5612 critter
->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5613 critter
->SetMaxHealth(1);
5614 critter
->SetHealth(1);
5615 critter
->SetLevel(1);
5617 // set timer for unsummon
5618 int32 duration
= GetSpellDuration(m_spellInfo
);
5620 critter
->SetDuration(duration
);
5622 std::string name
= player
->GetName();
5623 name
.append(petTypeSuffix
[critter
->getPetType()]);
5624 critter
->SetName( name
);
5625 player
->SetMiniPet(critter
);
5627 map
->Add((Creature
*)critter
);
5630 void Spell::EffectKnockBack(uint32 i
)
5632 if(!unitTarget
|| !m_caster
)
5635 // Effect only works on players
5636 if(unitTarget
->GetTypeId()!=TYPEID_PLAYER
)
5639 float vsin
= sin(m_caster
->GetAngle(unitTarget
));
5640 float vcos
= cos(m_caster
->GetAngle(unitTarget
));
5642 WorldPacket
data(SMSG_MOVE_KNOCK_BACK
, (8+4+4+4+4+4));
5643 data
.append(unitTarget
->GetPackGUID());
5644 data
<< uint32(0); // Sequence
5645 data
<< float(vcos
); // x direction
5646 data
<< float(vsin
); // y direction
5647 data
<< float(m_spellInfo
->EffectMiscValue
[i
])/10; // Horizontal speed
5648 data
<< float(damage
/-10); // Z Movement speed (vertical)
5650 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5653 void Spell::EffectSendTaxi(uint32 i
)
5655 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5658 TaxiPathEntry
const* entry
= sTaxiPathStore
.LookupEntry(m_spellInfo
->EffectMiscValue
[i
]);
5662 std::vector
<uint32
> nodes
;
5665 nodes
[0] = entry
->from
;
5666 nodes
[1] = entry
->to
;
5669 switch(m_spellInfo
->Id
)
5671 case 31606: //Stormcrow Amulet
5674 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5675 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5676 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5679 case 34905: //Stealth Flight
5684 ((Player
*)unitTarget
)->ActivateTaxiPathTo(nodes
,mountid
);
5688 void Spell::EffectPlayerPull(uint32 i
)
5690 if(!unitTarget
|| !m_caster
)
5693 // Effect only works on players
5694 if(unitTarget
->GetTypeId()!=TYPEID_PLAYER
)
5697 float vsin
= sin(unitTarget
->GetAngle(m_caster
));
5698 float vcos
= cos(unitTarget
->GetAngle(m_caster
));
5700 WorldPacket
data(SMSG_MOVE_KNOCK_BACK
, (8+4+4+4+4+4));
5701 data
.append(unitTarget
->GetPackGUID());
5702 data
<< uint32(0); // Sequence
5703 data
<< float(vcos
); // x direction
5704 data
<< float(vsin
); // y direction
5706 data
<< float(damage
? damage
: unitTarget
->GetDistance2d(m_caster
));
5707 data
<< float(m_spellInfo
->EffectMiscValue
[i
])/-10; // Z Movement speed
5709 ((Player
*)unitTarget
)->GetSession()->SendPacket(&data
);
5712 void Spell::EffectDispelMechanic(uint32 i
)
5717 uint32 mechanic
= m_spellInfo
->EffectMiscValue
[i
];
5719 Unit::AuraMap
& Auras
= unitTarget
->GetAuras();
5720 for(Unit::AuraMap::iterator iter
= Auras
.begin(), next
; iter
!= Auras
.end(); iter
= next
)
5724 SpellEntry
const *spell
= sSpellStore
.LookupEntry(iter
->second
->GetSpellProto()->Id
);
5725 if(spell
->Mechanic
== mechanic
|| spell
->EffectMechanic
[iter
->second
->GetEffIndex()] == mechanic
)
5727 unitTarget
->RemoveAurasDueToSpell(spell
->Id
);
5731 next
= Auras
.begin();
5737 void Spell::EffectSummonDeadPet(uint32
/*i*/)
5739 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5741 Player
*_player
= (Player
*)m_caster
;
5742 Pet
*pet
= _player
->GetPet();
5749 pet
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, 0);
5750 pet
->RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
);
5751 pet
->setDeathState( ALIVE
);
5752 pet
->clearUnitState(UNIT_STAT_ALL_STATE
);
5753 pet
->SetHealth( uint32(pet
->GetMaxHealth()*(float(damage
)/100)));
5755 pet
->AIM_Initialize();
5757 _player
->PetSpellInitialize();
5758 pet
->SavePetToDB(PET_SAVE_AS_CURRENT
);
5761 void Spell::EffectDestroyAllTotems(uint32
/*i*/)
5764 for(int slot
= 0; slot
< MAX_TOTEM
; ++slot
)
5766 if(!m_caster
->m_TotemSlot
[slot
])
5769 Creature
* totem
= ObjectAccessor::GetCreature(*m_caster
,m_caster
->m_TotemSlot
[slot
]);
5770 if(totem
&& totem
->isTotem())
5772 uint32 spell_id
= totem
->GetUInt32Value(UNIT_CREATED_BY_SPELL
);
5773 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(spell_id
);
5775 mana
+= spellInfo
->manaCost
* damage
/ 100;
5776 ((Totem
*)totem
)->UnSummon();
5780 int32 gain
= m_caster
->ModifyPower(POWER_MANA
,int32(mana
));
5781 m_caster
->SendEnergizeSpellLog(m_caster
, m_spellInfo
->Id
, gain
, POWER_MANA
);
5784 void Spell::EffectDurabilityDamage(uint32 i
)
5786 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5789 int32 slot
= m_spellInfo
->EffectMiscValue
[i
];
5791 // FIXME: some spells effects have value -1/-2
5792 // Possibly its mean -1 all player equipped items and -2 all items
5795 ((Player
*)unitTarget
)->DurabilityPointsLossAll(damage
,(slot
< -1));
5799 // invalid slot value
5800 if(slot
>= INVENTORY_SLOT_BAG_END
)
5803 if(Item
* item
= ((Player
*)unitTarget
)->GetItemByPos(INVENTORY_SLOT_BAG_0
,slot
))
5804 ((Player
*)unitTarget
)->DurabilityPointsLoss(item
,damage
);
5807 void Spell::EffectDurabilityDamagePCT(uint32 i
)
5809 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
5812 int32 slot
= m_spellInfo
->EffectMiscValue
[i
];
5814 // FIXME: some spells effects have value -1/-2
5815 // Possibly its mean -1 all player equipped items and -2 all items
5818 ((Player
*)unitTarget
)->DurabilityLossAll(double(damage
)/100.0f
,(slot
< -1));
5822 // invalid slot value
5823 if(slot
>= INVENTORY_SLOT_BAG_END
)
5829 if(Item
* item
= ((Player
*)unitTarget
)->GetItemByPos(INVENTORY_SLOT_BAG_0
,slot
))
5830 ((Player
*)unitTarget
)->DurabilityLoss(item
,double(damage
)/100.0f
);
5833 void Spell::EffectModifyThreatPercent(uint32
/*effIndex*/)
5838 unitTarget
->getThreatManager().modifyThreatPercent(m_caster
, damage
);
5841 void Spell::EffectTransmitted(uint32 effIndex
)
5843 uint32 name_id
= m_spellInfo
->EffectMiscValue
[effIndex
];
5845 GameObjectInfo
const* goinfo
= objmgr
.GetGameObjectInfo(name_id
);
5849 sLog
.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id
, m_spellInfo
->Id
);
5855 if(m_targets
.m_targetMask
& TARGET_FLAG_DEST_LOCATION
)
5857 fx
= m_targets
.m_destX
;
5858 fy
= m_targets
.m_destY
;
5859 fz
= m_targets
.m_destZ
;
5861 //FIXME: this can be better check for most objects but still hack
5862 else if(m_spellInfo
->EffectRadiusIndex
[effIndex
] && m_spellInfo
->speed
==0)
5864 float dis
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(m_spellInfo
->EffectRadiusIndex
[effIndex
]));
5865 m_caster
->GetClosePoint(fx
,fy
,fz
,DEFAULT_WORLD_OBJECT_SIZE
, dis
);
5869 float min_dis
= GetSpellMinRange(sSpellRangeStore
.LookupEntry(m_spellInfo
->rangeIndex
));
5870 float max_dis
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(m_spellInfo
->rangeIndex
));
5871 float dis
= rand_norm() * (max_dis
- min_dis
) + min_dis
;
5873 m_caster
->GetClosePoint(fx
,fy
,fz
,DEFAULT_WORLD_OBJECT_SIZE
, dis
);
5876 Map
*cMap
= m_caster
->GetMap();
5878 if(goinfo
->type
==GAMEOBJECT_TYPE_FISHINGNODE
)
5880 if ( !cMap
->IsInWater(fx
,fy
,fz
-0.5f
)) // Hack to prevent fishing bobber from failing to land on fishing hole
5881 { // but this is not proper, we really need to ignore not materialized objects
5882 SendCastResult(SPELL_FAILED_NOT_HERE
);
5883 SendChannelUpdate(0);
5887 // replace by water level in this case
5888 fz
= cMap
->GetWaterLevel(fx
,fy
);
5890 // if gameobject is summoning object, it should be spawned right on caster's position
5891 else if(goinfo
->type
==GAMEOBJECT_TYPE_SUMMONING_RITUAL
)
5893 m_caster
->GetPosition(fx
,fy
,fz
);
5896 GameObject
* pGameObj
= new GameObject
;
5898 if(!pGameObj
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), name_id
, cMap
,
5899 fx
, fy
, fz
, m_caster
->GetOrientation(), 0, 0, 0, 0, 100, 1))
5905 int32 duration
= GetSpellDuration(m_spellInfo
);
5907 switch(goinfo
->type
)
5909 case GAMEOBJECT_TYPE_FISHINGNODE
:
5911 m_caster
->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
,pGameObj
->GetGUID());
5913 pGameObj
->SetFloatValue(GAMEOBJECT_ROTATION
+ 2, 0.88431775569915771 );
5915 pGameObj
->SetFloatValue(GAMEOBJECT_ROTATION
+ 3, -0.4668855369091033 );
5916 m_caster
->AddGameObject(pGameObj
); // will removed at spell cancel
5918 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5919 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5923 case 0: lastSec
= 3; break;
5924 case 1: lastSec
= 7; break;
5925 case 2: lastSec
= 13; break;
5926 case 3: lastSec
= 17; break;
5929 duration
= duration
- lastSec
*1000 + FISHING_BOBBER_READY_TIME
*1000;
5932 case GAMEOBJECT_TYPE_SUMMONING_RITUAL
:
5934 if(m_caster
->GetTypeId()==TYPEID_PLAYER
)
5936 pGameObj
->AddUniqueUse((Player
*)m_caster
);
5937 m_caster
->AddGameObject(pGameObj
); // will removed at spell cancel
5941 case GAMEOBJECT_TYPE_FISHINGHOLE
:
5942 case GAMEOBJECT_TYPE_CHEST
:
5949 pGameObj
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
5951 pGameObj
->SetOwnerGUID(m_caster
->GetGUID() );
5953 pGameObj
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel() );
5954 pGameObj
->SetSpellId(m_spellInfo
->Id
);
5956 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
5957 //m_caster->AddGameObject(pGameObj);
5958 //m_ObjToDel.push_back(pGameObj);
5960 cMap
->Add(pGameObj
);
5962 WorldPacket
data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE
, 8);
5963 data
<< uint64(pGameObj
->GetGUID());
5964 m_caster
->SendMessageToSet(&data
,true);
5966 if(uint32 linkedEntry
= pGameObj
->GetLinkedGameObjectEntry())
5968 GameObject
* linkedGO
= new GameObject
;
5969 if(linkedGO
->Create(objmgr
.GenerateLowGuid(HIGHGUID_GAMEOBJECT
), linkedEntry
, cMap
,
5970 fx
, fy
, fz
, m_caster
->GetOrientation(), 0, 0, 0, 0, 100, 1))
5972 linkedGO
->SetRespawnTime(duration
> 0 ? duration
/1000 : 0);
5973 linkedGO
->SetUInt32Value(GAMEOBJECT_LEVEL
, m_caster
->getLevel() );
5974 linkedGO
->SetSpellId(m_spellInfo
->Id
);
5975 linkedGO
->SetOwnerGUID(m_caster
->GetGUID() );
5977 linkedGO
->GetMap()->Add(linkedGO
);
5988 void Spell::EffectProspecting(uint32
/*i*/)
5990 if(m_caster
->GetTypeId() != TYPEID_PLAYER
)
5993 Player
* p_caster
= (Player
*)m_caster
;
5994 if(!itemTarget
|| !(itemTarget
->GetProto()->BagFamily
& BAG_FAMILY_MASK_MINING_SUPP
))
5997 if(itemTarget
->GetCount() < 5)
6000 if( sWorld
.getConfig(CONFIG_SKILL_PROSPECTING
))
6002 uint32 SkillValue
= p_caster
->GetPureSkillValue(SKILL_JEWELCRAFTING
);
6003 uint32 reqSkillValue
= itemTarget
->GetProto()->RequiredSkillRank
;
6004 p_caster
->UpdateGatherSkill(SKILL_JEWELCRAFTING
, SkillValue
, reqSkillValue
);
6007 ((Player
*)m_caster
)->SendLoot(itemTarget
->GetGUID(), LOOT_PROSPECTING
);
6010 void Spell::EffectSkill(uint32
/*i*/)
6012 sLog
.outDebug("WORLD: SkillEFFECT");
6015 void Spell::EffectSummonDemon(uint32 i
)
6017 float px
= m_targets
.m_destX
;
6018 float py
= m_targets
.m_destY
;
6019 float pz
= m_targets
.m_destZ
;
6021 Creature
* Charmed
= m_caster
->SummonCreature(m_spellInfo
->EffectMiscValue
[i
], px
, py
, pz
, m_caster
->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
,3600000);
6025 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6026 Charmed
->SetLevel(m_caster
->getLevel());
6028 // TODO: Add damage/mana/hp according to level
6030 if (m_spellInfo
->EffectMiscValue
[i
] == 89) // Inferno summon
6032 // Enslave demon effect, without mana cost and cooldown
6033 m_caster
->CastSpell(Charmed
, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6036 Charmed
->CastSpell(Charmed
, 22703, true, 0);
6040 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6041 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6042 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6043 This is why we use a half sec delay between the visual effect and the resurrection itself */
6044 void Spell::EffectSpiritHeal(uint32
/*i*/)
6047 if(!unitTarget || unitTarget->isAlive())
6049 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6051 if(!unitTarget->IsInWorld())
6054 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6055 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6056 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6057 ((Player*)unitTarget)->SpawnCorpseBones();
6061 // remove insignia spell effect
6062 void Spell::EffectSkinPlayerCorpse(uint32
/*i*/)
6064 sLog
.outDebug("Effect: SkinPlayerCorpse");
6065 if ( (m_caster
->GetTypeId() != TYPEID_PLAYER
) || (unitTarget
->GetTypeId() != TYPEID_PLAYER
) || (unitTarget
->isAlive()) )
6068 ((Player
*)unitTarget
)->RemovedInsignia( (Player
*)m_caster
);
6071 void Spell::EffectStealBeneficialBuff(uint32 i
)
6073 sLog
.outDebug("Effect: StealBeneficialBuff");
6075 if(!unitTarget
|| unitTarget
==m_caster
) // can't steal from self
6078 std::vector
<Aura
*> steal_list
;
6079 // Create dispel mask by dispel type
6080 uint32 dispelMask
= GetDispellMask( DispelType(m_spellInfo
->EffectMiscValue
[i
]) );
6081 Unit::AuraMap
const& auras
= unitTarget
->GetAuras();
6082 for(Unit::AuraMap::const_iterator itr
= auras
.begin(); itr
!= auras
.end(); ++itr
)
6084 Aura
*aur
= (*itr
).second
;
6085 if (aur
&& (1<<aur
->GetSpellProto()->Dispel
) & dispelMask
)
6087 // Need check for passive? this
6088 if (aur
->IsPositive() && !aur
->IsPassive())
6089 steal_list
.push_back(aur
);
6092 // Ok if exist some buffs for dispel try dispel it
6093 if (!steal_list
.empty())
6095 std::list
< std::pair
<uint32
,uint64
> > success_list
;
6096 int32 list_size
= steal_list
.size();
6097 // Dispell N = damage buffs (or while exist buffs for dispel)
6098 for (int32 count
=0; count
< damage
&& list_size
> 0; ++count
)
6100 // Random select buff for dispel
6101 Aura
*aur
= steal_list
[urand(0, list_size
-1)];
6102 // Not use chance for steal
6103 // TODO possible need do it
6104 success_list
.push_back( std::pair
<uint32
,uint64
>(aur
->GetId(),aur
->GetCasterGUID()));
6106 // Remove buff from list for prevent doubles
6107 for (std::vector
<Aura
*>::iterator j
= steal_list
.begin(); j
!= steal_list
.end(); )
6110 if (stealed
->GetId() == aur
->GetId() && stealed
->GetCasterGUID() == aur
->GetCasterGUID())
6112 j
= steal_list
.erase(j
);
6119 // Really try steal and send log
6120 if (!success_list
.empty())
6122 int32 count
= success_list
.size();
6123 WorldPacket
data(SMSG_SPELLSTEALLOG
, 8+8+4+1+4+count
*5);
6124 data
.append(unitTarget
->GetPackGUID()); // Victim GUID
6125 data
.append(m_caster
->GetPackGUID()); // Caster GUID
6126 data
<< uint32(m_spellInfo
->Id
); // Dispell spell id
6127 data
<< uint8(0); // not used
6128 data
<< uint32(count
); // count
6129 for (std::list
<std::pair
<uint32
,uint64
> >::iterator j
= success_list
.begin(); j
!= success_list
.end(); ++j
)
6131 SpellEntry
const* spellInfo
= sSpellStore
.LookupEntry(j
->first
);
6132 data
<< uint32(spellInfo
->Id
); // Spell Id
6133 data
<< uint8(0); // 0 - steals !=0 transfers
6134 unitTarget
->RemoveAurasDueToSpellBySteal(spellInfo
->Id
, j
->second
, m_caster
);
6136 m_caster
->SendMessageToSet(&data
, true);
6141 void Spell::EffectKillCredit(uint32 i
)
6143 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
6146 ((Player
*)unitTarget
)->KilledMonster(m_spellInfo
->EffectMiscValue
[i
], 0);
6149 void Spell::EffectQuestFail(uint32 i
)
6151 if(!unitTarget
|| unitTarget
->GetTypeId() != TYPEID_PLAYER
)
6154 ((Player
*)unitTarget
)->FailQuest(m_spellInfo
->EffectMiscValue
[i
]);