[8056] Move SMSG_CLEAR_COOLDOWN into function and use it. Other cleanups.
[getmangos.git] / src / game / Unit.cpp
blob1dc479bb4515c606771ea8c121349dd6042f909c
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Log.h"
21 #include "Opcodes.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "World.h"
25 #include "ObjectMgr.h"
26 #include "SpellMgr.h"
27 #include "Unit.h"
28 #include "QuestDef.h"
29 #include "Player.h"
30 #include "Creature.h"
31 #include "Spell.h"
32 #include "Group.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
37 #include "Formulas.h"
38 #include "Pet.h"
39 #include "Util.h"
40 #include "Totem.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
44 #include "CellImpl.h"
45 #include "Path.h"
46 #include "Traveller.h"
48 #include <math.h>
50 float baseMoveSpeed[MAX_MOVE_TYPE] =
52 2.5f, // MOVE_WALK
53 7.0f, // MOVE_RUN
54 1.25f, // MOVE_RUN_BACK
55 4.722222f, // MOVE_SWIM
56 4.5f, // MOVE_SWIM_BACK
57 3.141594f, // MOVE_TURN_RATE
58 7.0f, // MOVE_FLIGHT
59 4.5f, // MOVE_FLIGHT_BACK
60 3.14f // MOVE_PITCH_RATE
63 // Used for prepare can/can`t triggr aura
64 static bool InitTriggerAuraData();
65 // Define can trigger auras
66 static bool isTriggerAura[TOTAL_AURAS];
67 // Define can`t trigger auras (need for disable second trigger)
68 static bool isNonTriggerAura[TOTAL_AURAS];
69 // Prepare lists
70 static bool procPrepared = InitTriggerAuraData();
72 Unit::Unit()
73 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
75 m_objectType |= TYPEMASK_UNIT;
76 m_objectTypeId = TYPEID_UNIT;
78 m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION);
80 m_attackTimer[BASE_ATTACK] = 0;
81 m_attackTimer[OFF_ATTACK] = 0;
82 m_attackTimer[RANGED_ATTACK] = 0;
83 m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
84 m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
85 m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
87 m_extraAttacks = 0;
89 m_state = 0;
90 m_form = FORM_NONE;
91 m_deathState = ALIVE;
93 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
94 m_currentSpells[i] = NULL;
96 m_addDmgOnce = 0;
98 for(int i = 0; i < MAX_TOTEM; ++i)
99 m_TotemSlot[i] = 0;
101 m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
102 //m_Aura = NULL;
103 //m_AurasCheck = 2000;
104 //m_removeAuraTimer = 4;
105 //tmpAura = NULL;
107 m_Visibility = VISIBILITY_ON;
109 m_detectInvisibilityMask = 0;
110 m_invisibilityMask = 0;
111 m_transform = 0;
112 m_ShapeShiftFormSpellId = 0;
113 m_canModifyStats = false;
115 for (int i = 0; i < MAX_SPELL_IMMUNITY; ++i)
116 m_spellImmune[i].clear();
117 for (int i = 0; i < UNIT_MOD_END; ++i)
119 m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
120 m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
121 m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
122 m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
124 // implement 50% base damage from offhand
125 m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
127 for (int i = 0; i < MAX_ATTACK; ++i)
129 m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
130 m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
132 for (int i = 0; i < MAX_STATS; ++i)
133 m_createStats[i] = 0.0f;
135 m_attacking = NULL;
136 m_modMeleeHitChance = 0.0f;
137 m_modRangedHitChance = 0.0f;
138 m_modSpellHitChance = 0.0f;
139 m_baseSpellCritChance = 5;
141 m_CombatTimer = 0;
142 m_lastManaUse = 0;
144 //m_victimThreat = 0.0f;
145 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
146 m_threatModifier[i] = 1.0f;
147 m_isSorted = true;
148 for (int i = 0; i < MAX_MOVE_TYPE; ++i)
149 m_speed_rate[i] = 1.0f;
151 m_removedAuras = 0;
152 m_charmInfo = NULL;
153 m_unit_movement_flags = 0;
155 // remove aurastates allowing special moves
156 for(int i=0; i < MAX_REACTIVE; ++i)
157 m_reactiveTimer[i] = 0;
160 Unit::~Unit()
162 // set current spells as deletable
163 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
165 if (m_currentSpells[i])
167 m_currentSpells[i]->SetReferencedFromCurrent(false);
168 m_currentSpells[i] = NULL;
172 RemoveAllGameObjects();
173 RemoveAllDynObjects();
175 if(m_charmInfo) delete m_charmInfo;
178 void Unit::Update( uint32 p_time )
180 /*if(p_time > m_AurasCheck)
182 m_AurasCheck = 2000;
183 _UpdateAura();
184 }else
185 m_AurasCheck -= p_time;*/
187 // WARNING! Order of execution here is important, do not change.
188 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
189 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
190 m_Events.Update( p_time );
191 _UpdateSpells( p_time );
193 // update combat timer only for players and pets
194 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed()))
196 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
197 // targets without stopping half way there and running off.
198 // These flags are reset after target dies or another command is given.
199 if( m_HostilRefManager.isEmpty() )
201 // m_CombatTimer set at aura start and it will be freeze until aura removing
202 if ( m_CombatTimer <= p_time )
203 ClearInCombat();
204 else
205 m_CombatTimer -= p_time;
209 if(uint32 base_att = getAttackTimer(BASE_ATTACK))
211 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
214 // update abilities available only for fraction of time
215 UpdateReactives( p_time );
217 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth()*0.20f);
218 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, GetHealth() < GetMaxHealth()*0.35f);
219 ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetHealth() > GetMaxHealth()*0.75f);
221 i_motionMaster.UpdateMotion(p_time);
224 bool Unit::haveOffhandWeapon() const
226 if(GetTypeId() == TYPEID_PLAYER)
227 return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true);
228 else
229 return false;
232 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player)
234 float x, y, z;
235 if(GetMotionMaster()->GetDestination(x, y, z))
236 SendMonsterMoveWithSpeed(x, y, z, 0, player);
239 void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player)
241 if (!transitTime)
243 if(GetTypeId()==TYPEID_PLAYER)
245 Traveller<Player> traveller(*(Player*)this);
246 transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
248 else
250 Traveller<Creature> traveller(*(Creature*)this);
251 transitTime = traveller.GetTotalTrevelTimeTo(x,y,z);
254 //float orientation = (float)atan2((double)dy, (double)dx);
255 SendMonsterMove(x, y, z, 0, GetUnitMovementFlags(), transitTime, player);
258 void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player)
260 float moveTime = Time;
262 WorldPacket data( SMSG_MONSTER_MOVE, (41 + GetPackGUID().size()) );
263 data.append(GetPackGUID());
264 data << uint8(0); // new in 3.1
265 data << GetPositionX() << GetPositionY() << GetPositionZ();
266 data << uint32(getMSTime());
268 data << uint8(type); // unknown
269 switch(type)
271 case 0: // normal packet
272 break;
273 case 1: // stop packet (raw pos?)
274 SendMessageToSet( &data, true );
275 return;
276 case 2: // facing spot, not used currently
277 data << float(0);
278 data << float(0);
279 data << float(0);
280 break;
281 case 3: // not used currently
282 data << uint64(0); // probably target guid (facing target?)
283 break;
284 case 4: // not used currently
285 data << float(0); // facing angle
286 break;
289 data << uint32(MovementFlags);
291 if(MovementFlags & MONSTER_MOVE_WALK)
292 moveTime *= 1.05f;
294 data << uint32(moveTime); // Time in between points
295 data << uint32(1); // 1 single waypoint
296 data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B
298 if(player)
299 player->GetSession()->SendPacket(&data);
300 else
301 SendMessageToSet( &data, true );
304 void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags)
306 uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32);
308 uint32 pathSize = end - start;
310 WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3) );
311 data.append(GetPackGUID());
312 data << uint8(0);
313 data << GetPositionX();
314 data << GetPositionY();
315 data << GetPositionZ();
316 data << uint32(getMSTime());
317 data << uint8( 0 );
318 data << uint32( MovementFlags );
319 data << uint32( traveltime );
320 data << uint32( pathSize );
321 data.append( (char*)path.GetNodes(start), pathSize * 4 * 3 );
322 SendMessageToSet(&data, true);
325 void Unit::resetAttackTimer(WeaponAttackType type)
327 m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
330 bool Unit::canReachWithAttack(Unit *pVictim) const
332 assert(pVictim);
333 float reach = GetFloatValue(UNIT_FIELD_COMBATREACH);
334 if( reach <= 0.0f )
335 reach = 1.0f;
336 return IsWithinDistInMap(pVictim, reach);
339 void Unit::RemoveSpellsCausingAura(AuraType auraType)
341 if (auraType >= TOTAL_AURAS) return;
342 AuraList::const_iterator iter, next;
343 for (iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end(); iter = next)
345 next = iter;
346 ++next;
348 if (*iter)
350 RemoveAurasDueToSpell((*iter)->GetId());
351 if (!m_modAuras[auraType].empty())
352 next = m_modAuras[auraType].begin();
353 else
354 return;
359 bool Unit::HasAuraType(AuraType auraType) const
361 return (!m_modAuras[auraType].empty());
364 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
365 void Unit::RemoveSpellbyDamageTaken(AuraType auraType, uint32 damage)
367 if(!HasAuraType(auraType))
368 return;
370 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
371 uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
372 float chance = float(damage) / max_dmg * 100.0f;
373 if (roll_chance_f(chance))
374 RemoveSpellsCausingAura(auraType);
377 void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
379 if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
381 if(absorb)
382 absorb += damage;
383 damage = 0;
384 return;
387 //You don't lose health from damage taken from another player while in a sanctuary
388 //You still see it in the combat log though
389 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
391 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
392 if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
394 if(absorb)
395 absorb += damage;
396 damage = 0;
400 uint32 originalDamage = damage;
402 //Script Event damage Deal
403 if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
404 ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
405 //Script Event damage taken
406 if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->AI() )
407 ((Creature *)pVictim)->AI()->DamageTaken(this, damage);
409 if(absorb && originalDamage > damage)
410 absorb += (originalDamage - damage);
413 uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
415 // remove affects from victim (including from 0 damage and DoTs)
416 if(pVictim != this)
417 pVictim->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
419 // remove affects from attacker at any non-DoT damage (including 0 damage)
420 if( damagetype != DOT)
422 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
423 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
425 if(pVictim != this)
426 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY);
428 if(pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->IsStandState() && !pVictim->hasUnitState(UNIT_STAT_STUNNED))
429 pVictim->SetStandState(UNIT_STAND_STATE_STAND);
432 if(!damage)
434 // Rage from physical damage received .
435 if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
436 ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
438 return 0;
440 if (!spellProto || !IsAuraAddedBySpell(SPELL_AURA_MOD_FEAR, spellProto->Id))
441 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR, damage);
442 // root type spells do not dispel the root effect
443 if (!spellProto || !(spellProto->Mechanic == MECHANIC_ROOT || IsAuraAddedBySpell(SPELL_AURA_MOD_ROOT, spellProto->Id)))
444 pVictim->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT, damage);
446 // no xp,health if type 8 /critters/
447 if(pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER)
449 pVictim->setDeathState(JUST_DIED);
450 pVictim->SetHealth(0);
452 // allow loot only if has loot_id in creature_template
453 CreatureInfo const* cInfo = ((Creature*)pVictim)->GetCreatureInfo();
454 if(cInfo && cInfo->lootid)
455 pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
457 // some critters required for quests
458 if(GetTypeId() == TYPEID_PLAYER)
459 ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
461 return damage;
464 DEBUG_LOG("DealDamageStart");
466 uint32 health = pVictim->GetHealth();
467 sLog.outDetail("deal dmg:%d to health:%d ",damage,health);
469 // duel ends when player has 1 or less hp
470 bool duel_hasEnded = false;
471 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1))
473 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
474 if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetGUID() == GetOwnerGUID())
475 damage = health-1;
477 duel_hasEnded = true;
479 //Get in CombatState
480 if(pVictim != this && damagetype != DOT)
482 SetInCombatWith(pVictim);
483 pVictim->SetInCombatWith(this);
485 if(Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself())
486 SetContestedPvP(attackedPlayer);
489 // Rage from Damage made (only from direct weapon damage)
490 if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
492 uint32 weaponSpeedHitFactor;
494 switch(cleanDamage->attackType)
496 case BASE_ATTACK:
498 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
499 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 7);
500 else
501 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
503 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
505 break;
507 case OFF_ATTACK:
509 if(cleanDamage->hitOutCome == MELEE_HIT_CRIT)
510 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
511 else
512 weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
514 ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
516 break;
518 case RANGED_ATTACK:
519 break;
523 if (GetTypeId() == TYPEID_PLAYER && this != pVictim)
525 Player *killer = ((Player*)this);
527 // in bg, count dmg if victim is also a player
528 if (pVictim->GetTypeId()==TYPEID_PLAYER)
530 if (BattleGround *bg = killer->GetBattleGround())
532 // FIXME: kept by compatibility. don't know in BG if the restriction apply.
533 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
537 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim);
538 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
541 if (pVictim->GetTypeId() == TYPEID_PLAYER)
542 ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage);
544 if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient())
545 ((Creature*)pVictim)->SetLootRecipient(this);
547 if (health <= damage)
549 DEBUG_LOG("DealDamage: victim just died");
551 if (pVictim->GetTypeId() == TYPEID_PLAYER)
552 ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
554 // find player: owner of controlled `this` or `this` itself maybe
555 Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
557 if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient())
558 player = ((Creature*)pVictim)->GetLootRecipient();
559 // Reward player, his pets, and group/raid members
560 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
561 if(player && player!=pVictim)
563 player->RewardPlayerAndGroupAtKill(pVictim);
564 player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
567 DEBUG_LOG("DealDamageAttackStop");
569 // stop combat
570 pVictim->CombatStop();
571 pVictim->getHostilRefManager().deleteReferences();
573 bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795;
575 // if talent known but not triggered (check priest class for speedup check)
576 Aura* spiritOfRedemtionTalentReady = NULL;
577 if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
578 pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
580 AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
581 for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
583 if((*itr)->GetSpellProto()->SpellIconID==1654)
585 spiritOfRedemtionTalentReady = *itr;
586 break;
591 DEBUG_LOG("SET JUST_DIED");
592 if(!spiritOfRedemtionTalentReady)
593 pVictim->setDeathState(JUST_DIED);
595 DEBUG_LOG("DealDamageHealth1");
597 if(spiritOfRedemtionTalentReady)
599 // save value before aura remove
600 uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
601 if(!ressSpellId)
602 ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId();
604 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
605 pVictim->RemoveAllAurasOnDeath();
607 // restore for use at real death
608 pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId);
610 // FORM_SPIRITOFREDEMPTION and related auras
611 pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady);
613 else
614 pVictim->SetHealth(0);
616 // remember victim PvP death for corpse type and corpse reclaim delay
617 // at original death (not at SpiritOfRedemtionTalent timeout)
618 if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent )
619 ((Player*)pVictim)->SetPvPDeath(player!=NULL);
621 // Call KilledUnit for creatures
622 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI())
623 ((Creature*)this)->AI()->KilledUnit(pVictim);
625 // achievement stuff
626 if (pVictim->GetTypeId() == TYPEID_PLAYER)
628 if (GetTypeId() == TYPEID_UNIT)
629 ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
630 else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
631 ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
634 // 10% durability loss on death
635 // clean InHateListOf
636 if (pVictim->GetTypeId() == TYPEID_PLAYER)
638 // only if not player and not controlled by player pet. And not at BG
639 if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround())
641 DEBUG_LOG("We are dead, loosing 10 percents durability");
642 ((Player*)pVictim)->DurabilityLossAll(0.10f,false);
643 // durability lost message
644 WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
645 ((Player*)pVictim)->GetSession()->SendPacket(&data);
648 else // creature died
650 DEBUG_LOG("DealDamageNotPlayer");
651 Creature *cVictim = (Creature*)pVictim;
653 if(!cVictim->isPet())
655 cVictim->DeleteThreatList();
656 cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
658 // Call creature just died function
659 if (cVictim->AI())
660 cVictim->AI()->JustDied(this);
662 // Dungeon specific stuff, only applies to players killing creatures
663 if(cVictim->GetInstanceId())
665 Map *m = cVictim->GetMap();
666 Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
667 // TODO: do instance binding anyway if the charmer/owner is offline
669 if(m->IsDungeon() && creditedPlayer)
671 if(m->IsRaid() || m->IsHeroic())
673 if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
674 ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);
676 else
678 // the reset time is set but not added to the scheduler
679 // until the players leave the instance
680 time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR;
681 if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId()))
682 if(save->GetResetTime() < resettime) save->SetResetTime(resettime);
688 // last damage from non duel opponent or opponent controlled creature
689 if(duel_hasEnded)
691 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
692 Player *he = (Player*)pVictim;
694 assert(he->duel);
696 he->duel->opponent->CombatStopWithPets(true);
697 he->CombatStopWithPets(true);
699 he->DuelComplete(DUEL_INTERUPTED);
702 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
703 if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->InBattleGround())
705 Player *killed = ((Player*)pVictim);
706 if(BattleGround *bg = killed->GetBattleGround())
707 if(player)
708 bg->HandleKillPlayer(killed, player);
709 //later we can add support for creature->player kills here i'm
710 //not sure, but i guess those kills also get counted in av
711 //else if(GetTypeId() == TYPEID_UNIT)
712 // bg->HandleKillPlayer(killed,(Creature*)this);
715 else // if (health <= damage)
717 DEBUG_LOG("DealDamageAlive");
719 if (pVictim->GetTypeId() == TYPEID_PLAYER)
720 ((Player*)pVictim)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
722 pVictim->ModifyHealth(- (int32)damage);
724 if(damagetype != DOT)
726 if(!getVictim())
728 // if not have main target then attack state with target (including AI call)
729 //start melee attacks only after melee hit
730 Attack(pVictim,(damagetype == DIRECT_DAMAGE));
733 // if damage pVictim call AI reaction
734 if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI())
735 ((Creature*)pVictim)->AI()->AttackedBy(this);
738 // polymorphed and other negative transformed cases
739 if(pVictim->getTransForm() && pVictim->hasUnitState(UNIT_STAT_CONFUSED))
740 pVictim->RemoveAurasDueToSpell(pVictim->getTransForm());
742 if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
744 if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
745 pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
747 if (pVictim->GetTypeId() != TYPEID_PLAYER)
749 if(spellProto && IsDamageToThreatSpell(spellProto))
750 pVictim->AddThreat(this, damage*2, damageSchoolMask, spellProto);
751 else
752 pVictim->AddThreat(this, damage, damageSchoolMask, spellProto);
754 else // victim is a player
756 // Rage from damage received
757 if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
759 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
760 ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
763 // random durability for items (HIT TAKEN)
764 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
766 EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1));
767 ((Player*)pVictim)->DurabilityPointLossForEquipSlot(slot);
771 if(GetTypeId()==TYPEID_PLAYER)
773 // random durability for items (HIT DONE)
774 if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
776 EquipmentSlots slot = EquipmentSlots(urand(0,EQUIPMENT_SLOT_END-1));
777 ((Player*)this)->DurabilityPointLossForEquipSlot(slot);
781 // TODO: Store auras by interrupt flag to speed this up.
782 AuraMap& vAuras = pVictim->GetAuras();
783 for (AuraMap::const_iterator i = vAuras.begin(), next; i != vAuras.end(); i = next)
785 const SpellEntry *se = i->second->GetSpellProto();
786 next = i; ++next;
787 if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self
788 continue;
789 if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
791 bool remove = true;
792 if (se->procFlags & (1<<3))
794 if (!roll_chance_i(se->procChance))
795 remove = false;
797 if (remove)
799 pVictim->RemoveAurasDueToSpell(i->second->GetId());
800 // FIXME: this may cause the auras with proc chance to be rerolled several times
801 next = vAuras.begin();
806 if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER)
808 if( damagetype != DOT )
810 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
812 // skip channeled spell (processed differently below)
813 if (i == CURRENT_CHANNELED_SPELL)
814 continue;
816 if(Spell* spell = pVictim->m_currentSpells[i])
817 if(spell->getState() == SPELL_STATE_PREPARING)
819 if(spell->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
820 pVictim->InterruptSpell(i);
821 else
822 spell->Delayed();
827 if(Spell* spell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
829 if (spell->getState() == SPELL_STATE_CASTING)
831 uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags;
832 if( channelInterruptFlags & CHANNEL_FLAG_DELAY )
834 if(pVictim!=this) //don't shorten the duration of channeling if you damage yourself
835 spell->DelayedChannel();
837 else if( (channelInterruptFlags & (CHANNEL_FLAG_DAMAGE | CHANNEL_FLAG_DAMAGE2)) )
839 sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id);
840 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
843 else if (spell->getState() == SPELL_STATE_DELAYED)
844 // break channeled spell in delayed state on damage
846 sLog.outDetail("Spell %u canceled at damage!",spell->m_spellInfo->Id);
847 pVictim->InterruptSpell(CURRENT_CHANNELED_SPELL);
852 // last damage from duel opponent
853 if(duel_hasEnded)
855 assert(pVictim->GetTypeId()==TYPEID_PLAYER);
856 Player *he = (Player*)pVictim;
858 assert(he->duel);
860 he->SetHealth(1);
862 he->duel->opponent->CombatStopWithPets(true);
863 he->CombatStopWithPets(true);
865 he->CastSpell(he, 7267, true); // beg
866 he->DuelComplete(DUEL_WON);
870 DEBUG_LOG("DealDamageEnd returned %d damage", damage);
872 return damage;
875 void Unit::CastStop(uint32 except_spellid)
877 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
878 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id!=except_spellid)
879 InterruptSpell(i,false);
882 void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
884 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
886 if(!spellInfo)
888 sLog.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
889 return;
892 CastSpell(Victim,spellInfo,triggered,castItem,triggeredByAura, originalCaster);
895 void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
897 if(!spellInfo)
899 sLog.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
900 return;
903 if (castItem)
904 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
906 if(!originalCaster && triggeredByAura)
907 originalCaster = triggeredByAura->GetCasterGUID();
909 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster );
911 SpellCastTargets targets;
912 targets.setUnitTarget( Victim );
913 spell->m_CastItem = castItem;
914 spell->prepare(&targets, triggeredByAura);
917 void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
919 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
921 if(!spellInfo)
923 sLog.outError("CastCustomSpell: unknown spell id %i", spellId);
924 return;
927 CastCustomSpell(Victim,spellInfo,bp0,bp1,bp2,triggered,castItem,triggeredByAura, originalCaster);
930 void Unit::CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
932 if(!spellInfo)
934 sLog.outError("CastCustomSpell: unknown spell");
935 return;
938 if (castItem)
939 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
941 if(!originalCaster && triggeredByAura)
942 originalCaster = triggeredByAura->GetCasterGUID();
944 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster);
946 if(bp0)
947 spell->m_currentBasePoints[0] = *bp0-int32(spellInfo->EffectBaseDice[0]);
949 if(bp1)
950 spell->m_currentBasePoints[1] = *bp1-int32(spellInfo->EffectBaseDice[1]);
952 if(bp2)
953 spell->m_currentBasePoints[2] = *bp2-int32(spellInfo->EffectBaseDice[2]);
955 SpellCastTargets targets;
956 targets.setUnitTarget( Victim );
957 spell->m_CastItem = castItem;
958 spell->prepare(&targets, triggeredByAura);
961 // used for scripting
962 void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
964 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
966 if(!spellInfo)
968 sLog.outError("CastSpell(x,y,z): unknown spell id %i by caster: %s %u)", spellId,(GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
969 return;
972 CastSpell(x, y, z,spellInfo,triggered,castItem,triggeredByAura, originalCaster);
975 // used for scripting
976 void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem, Aura* triggeredByAura, uint64 originalCaster)
978 if(!spellInfo)
980 sLog.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
981 return;
984 if (castItem)
985 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
987 if(!originalCaster && triggeredByAura)
988 originalCaster = triggeredByAura->GetCasterGUID();
990 Spell *spell = new Spell(this, spellInfo, triggered, originalCaster );
992 SpellCastTargets targets;
993 targets.setDestination(x, y, z);
994 spell->m_CastItem = castItem;
995 spell->prepare(&targets, triggeredByAura);
998 // Obsolete func need remove, here only for comotability vs another patches
999 uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage)
1001 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
1002 SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
1003 CalculateSpellDamage(&damageInfo, damage, spellInfo);
1004 DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
1005 SendSpellNonMeleeDamageLog(&damageInfo);
1006 DealSpellDamage(&damageInfo, true);
1007 return damageInfo.damage;
1010 void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
1012 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1013 Unit *pVictim = damageInfo->target;
1015 if (damage < 0)
1016 return;
1018 if(!this || !pVictim)
1019 return;
1020 if(!this->isAlive() || !pVictim->isAlive())
1021 return;
1023 uint32 crTypeMask = pVictim->GetCreatureTypeMask();
1024 // Check spell crit chance
1025 bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
1026 bool blocked = false;
1027 // Per-school calc
1028 switch (spellInfo->DmgClass)
1030 // Melee and Ranged Spells
1031 case SPELL_DAMAGE_CLASS_RANGED:
1032 case SPELL_DAMAGE_CLASS_MELEE:
1034 // Physical Damage
1035 if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
1037 //Calculate armor mitigation
1038 damage = CalcArmorReducedDamage(pVictim, damage);
1039 // Get blocked status
1040 blocked = isSpellBlocked(pVictim, spellInfo, attackType);
1042 // Magical Damage
1043 else
1045 // Calculate damage bonus
1046 damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1048 if (crit)
1050 damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
1052 // Calculate crit bonus
1053 uint32 crit_bonus = damage;
1054 // Apply crit_damage bonus for melee spells
1055 if(Player* modOwner = GetSpellModOwner())
1056 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1057 damage += crit_bonus;
1059 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1060 int32 critPctDamageMod=0;
1061 if(attackType == RANGED_ATTACK)
1062 critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
1063 else
1065 critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
1066 critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
1068 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1069 critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
1071 if (critPctDamageMod!=0)
1072 damage = int32((damage) * float((100.0f + critPctDamageMod)/100.0f));
1074 // Resilience - reduce crit damage
1075 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1076 damage -= ((Player*)pVictim)->GetMeleeCritDamageReduction(damage);
1078 // Spell weapon based damage CAN BE crit & blocked at same time
1079 if (blocked)
1081 damageInfo->blocked = uint32(pVictim->GetShieldBlockValue());
1082 if (damage < damageInfo->blocked)
1083 damageInfo->blocked = damage;
1084 damage-=damageInfo->blocked;
1087 break;
1088 // Magical Attacks
1089 case SPELL_DAMAGE_CLASS_NONE:
1090 case SPELL_DAMAGE_CLASS_MAGIC:
1092 // Calculate damage bonus
1093 damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1094 // If crit add critical bonus
1095 if (crit)
1097 damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
1098 damage = SpellCriticalDamageBonus(spellInfo, damage, pVictim);
1099 // Resilience - reduce crit damage
1100 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1101 damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage);
1104 break;
1107 // Calculate absorb resist
1108 if(damage > 0)
1110 // lookup absorb/resist ignore auras on caster for spell
1111 bool ignore = false;
1112 Unit::AuraList const& ignoreAbsorb = GetAurasByType(SPELL_AURA_MOD_IGNORE_ABSORB_FOR_SPELL);
1113 for(Unit::AuraList::const_iterator i = ignoreAbsorb.begin(); i != ignoreAbsorb.end(); ++i)
1114 if ((*i)->isAffectedOnSpell(spellInfo))
1116 ignore = true;
1117 break;
1120 if (!ignore)
1122 CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist);
1123 damage-= damageInfo->absorb + damageInfo->resist;
1126 else
1127 damage = 0;
1128 damageInfo->damage = damage;
1131 void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
1133 if (damageInfo==0)
1134 return;
1136 Unit *pVictim = damageInfo->target;
1138 if(!this || !pVictim)
1139 return;
1141 if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
1142 return;
1144 SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
1145 if (spellProto == NULL)
1147 sLog.outDebug("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID);
1148 return;
1151 //You don't lose health from damage taken from another player while in a sanctuary
1152 //You still see it in the combat log though
1153 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1155 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
1156 if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
1157 return;
1160 // Call default DealDamage
1161 CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
1162 DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
1165 //TODO for melee need create structure as in
1166 void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType)
1168 damageInfo->attacker = this;
1169 damageInfo->target = pVictim;
1170 damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
1171 damageInfo->attackType = attackType;
1172 damageInfo->damage = 0;
1173 damageInfo->cleanDamage = 0;
1174 damageInfo->absorb = 0;
1175 damageInfo->resist = 0;
1176 damageInfo->blocked_amount = 0;
1178 damageInfo->TargetState = 0;
1179 damageInfo->HitInfo = 0;
1180 damageInfo->procAttacker = PROC_FLAG_NONE;
1181 damageInfo->procVictim = PROC_FLAG_NONE;
1182 damageInfo->procEx = PROC_EX_NONE;
1183 damageInfo->hitOutCome = MELEE_HIT_EVADE;
1185 if(!this || !pVictim)
1186 return;
1187 if(!this->isAlive() || !pVictim->isAlive())
1188 return;
1190 // Select HitInfo/procAttacker/procVictim flag based on attack type
1191 switch (attackType)
1193 case BASE_ATTACK:
1194 damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT;
1195 damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;
1196 damageInfo->HitInfo = HITINFO_NORMALSWING2;
1197 break;
1198 case OFF_ATTACK:
1199 damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
1200 damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used
1201 damageInfo->HitInfo = HITINFO_LEFTSWING;
1202 break;
1203 case RANGED_ATTACK:
1204 damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
1205 damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
1206 damageInfo->HitInfo = 0x08;// test
1207 break;
1208 default:
1209 break;
1212 // Physical Immune check
1213 if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask)))
1215 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1216 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1218 damageInfo->procEx |=PROC_EX_IMMUNE;
1219 damageInfo->damage = 0;
1220 damageInfo->cleanDamage = 0;
1221 return;
1223 damage += CalculateDamage (damageInfo->attackType, false);
1224 // Add melee damage bonus
1225 MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
1226 // Calculate armor reduction
1227 damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
1228 damageInfo->cleanDamage += damage - damageInfo->damage;
1230 damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
1232 // Disable parry or dodge for ranged attack
1233 if(damageInfo->attackType == RANGED_ATTACK)
1235 if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL;
1236 if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS;
1239 switch(damageInfo->hitOutCome)
1241 case MELEE_HIT_EVADE:
1243 damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
1244 damageInfo->TargetState = VICTIMSTATE_EVADES;
1246 damageInfo->procEx|=PROC_EX_EVADE;
1247 damageInfo->damage = 0;
1248 damageInfo->cleanDamage = 0;
1249 return;
1251 case MELEE_HIT_MISS:
1253 damageInfo->HitInfo |= HITINFO_MISS;
1254 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1256 damageInfo->procEx|=PROC_EX_MISS;
1257 damageInfo->damage = 0;
1258 damageInfo->cleanDamage = 0;
1259 break;
1261 case MELEE_HIT_NORMAL:
1262 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1263 damageInfo->procEx|=PROC_EX_NORMAL_HIT;
1264 break;
1265 case MELEE_HIT_CRIT:
1267 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1268 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1270 damageInfo->procEx|=PROC_EX_CRITICAL_HIT;
1271 // Crit bonus calc
1272 damageInfo->damage += damageInfo->damage;
1273 int32 mod=0;
1274 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1275 if(damageInfo->attackType == RANGED_ATTACK)
1276 mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
1277 else
1279 mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
1280 mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
1283 uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
1285 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1286 mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
1287 if (mod!=0)
1288 damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f));
1290 // Resilience - reduce crit damage
1291 if (pVictim->GetTypeId()==TYPEID_PLAYER)
1293 uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(damageInfo->damage);
1294 damageInfo->damage -= resilienceReduction;
1295 damageInfo->cleanDamage += resilienceReduction;
1297 break;
1299 case MELEE_HIT_PARRY:
1300 damageInfo->TargetState = VICTIMSTATE_PARRY;
1301 damageInfo->procEx|=PROC_EX_PARRY;
1302 damageInfo->cleanDamage += damageInfo->damage;
1303 damageInfo->damage = 0;
1304 break;
1306 case MELEE_HIT_DODGE:
1307 damageInfo->TargetState = VICTIMSTATE_DODGE;
1308 damageInfo->procEx|=PROC_EX_DODGE;
1309 damageInfo->cleanDamage += damageInfo->damage;
1310 damageInfo->damage = 0;
1311 break;
1312 case MELEE_HIT_BLOCK:
1314 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1315 damageInfo->HitInfo |= HITINFO_BLOCK;
1316 damageInfo->procEx|=PROC_EX_BLOCK;
1317 damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
1318 if (damageInfo->blocked_amount >= damageInfo->damage)
1320 damageInfo->TargetState = VICTIMSTATE_BLOCKS;
1321 damageInfo->blocked_amount = damageInfo->damage;
1323 damageInfo->damage -= damageInfo->blocked_amount;
1324 damageInfo->cleanDamage += damageInfo->blocked_amount;
1325 break;
1327 case MELEE_HIT_GLANCING:
1329 damageInfo->HitInfo |= HITINFO_GLANCING;
1330 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1331 damageInfo->procEx|=PROC_EX_NORMAL_HIT;
1332 float reducePercent = 1.0f; //damage factor
1333 // calculate base values and mods
1334 float baseLowEnd = 1.3f;
1335 float baseHighEnd = 1.2f;
1336 switch(getClass()) // lowering base values for casters
1338 case CLASS_SHAMAN:
1339 case CLASS_PRIEST:
1340 case CLASS_MAGE:
1341 case CLASS_WARLOCK:
1342 case CLASS_DRUID:
1343 baseLowEnd -= 0.7f;
1344 baseHighEnd -= 0.3f;
1345 break;
1348 float maxLowEnd = 0.6f;
1349 switch(getClass()) // upper for melee classes
1351 case CLASS_WARRIOR:
1352 case CLASS_ROGUE:
1353 maxLowEnd = 0.91f; //If the attacker is a melee class then instead the lower value of 0.91
1356 // calculate values
1357 int32 diff = damageInfo->target->GetDefenseSkillValue() - GetWeaponSkillValue(damageInfo->attackType);
1358 float lowEnd = baseLowEnd - ( 0.05f * diff );
1359 float highEnd = baseHighEnd - ( 0.03f * diff );
1361 // apply max/min bounds
1362 if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
1363 lowEnd = 0.01f;
1364 else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
1365 lowEnd = maxLowEnd;
1367 if ( highEnd < 0.2f ) //high end limits
1368 highEnd = 0.2f;
1369 if ( highEnd > 0.99f )
1370 highEnd = 0.99f;
1372 if(lowEnd > highEnd) // prevent negative range size
1373 lowEnd = highEnd;
1375 reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
1377 damageInfo->cleanDamage += damageInfo->damage-uint32(reducePercent * damageInfo->damage);
1378 damageInfo->damage = uint32(reducePercent * damageInfo->damage);
1379 break;
1381 case MELEE_HIT_CRUSHING:
1383 damageInfo->HitInfo |= HITINFO_CRUSHING;
1384 damageInfo->TargetState = VICTIMSTATE_NORMAL;
1385 damageInfo->procEx|=PROC_EX_NORMAL_HIT;
1386 // 150% normal damage
1387 damageInfo->damage += (damageInfo->damage / 2);
1388 break;
1390 default:
1392 break;
1395 // Calculate absorb resist
1396 if(int32(damageInfo->damage) > 0)
1398 damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
1399 // Calculate absorb & resists
1400 CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
1401 damageInfo->damage-=damageInfo->absorb + damageInfo->resist;
1402 if (damageInfo->absorb)
1404 damageInfo->HitInfo|=HITINFO_ABSORB;
1405 damageInfo->procEx|=PROC_EX_ABSORB;
1407 if (damageInfo->resist)
1408 damageInfo->HitInfo|=HITINFO_RESIST;
1411 else // Umpossible get negative result but....
1412 damageInfo->damage = 0;
1415 void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
1417 if (damageInfo==0) return;
1418 Unit *pVictim = damageInfo->target;
1420 if(!this || !pVictim)
1421 return;
1423 if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
1424 return;
1426 //You don't lose health from damage taken from another player while in a sanctuary
1427 //You still see it in the combat log though
1428 if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
1430 const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
1431 if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
1432 return;
1435 // Hmmmm dont like this emotes client must by self do all animations
1436 if (damageInfo->HitInfo&HITINFO_CRITICALHIT)
1437 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
1438 if(damageInfo->blocked_amount && damageInfo->TargetState!=VICTIMSTATE_BLOCKS)
1439 pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
1441 if(damageInfo->TargetState == VICTIMSTATE_PARRY)
1443 // Get attack timers
1444 float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
1445 float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
1446 // Reduce attack time
1447 if (pVictim->haveOffhandWeapon() && offtime < basetime)
1449 float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f;
1450 float percent60 = 3.0f * percent20;
1451 if(offtime > percent20 && offtime <= percent60)
1453 pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1455 else if(offtime > percent60)
1457 offtime -= 2.0f * percent20;
1458 pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1461 else
1463 float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
1464 float percent60 = 3.0f * percent20;
1465 if(basetime > percent20 && basetime <= percent60)
1467 pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1469 else if(basetime > percent60)
1471 basetime -= 2.0f * percent20;
1472 pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1477 // Call default DealDamage
1478 CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
1479 DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
1481 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1482 if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) &&
1483 GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
1485 // -probability is between 0% and 40%
1486 // 20% base chance
1487 float Probability = 20.0f;
1489 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1490 if( pVictim->getLevel() < 30 )
1491 Probability = 0.65f*pVictim->getLevel()+0.5f;
1493 uint32 VictimDefense=pVictim->GetDefenseSkillValue();
1494 uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
1496 Probability *= AttackerMeleeSkill/(float)VictimDefense;
1498 if(Probability > 40.0f)
1499 Probability = 40.0f;
1501 if(roll_chance_f(Probability))
1502 CastSpell(pVictim, 1604, true);
1505 // If not miss
1506 if (!(damageInfo->HitInfo & HITINFO_MISS))
1508 // on weapon hit casts
1509 if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
1510 ((Player*)this)->CastItemCombatSpell(pVictim, damageInfo->attackType);
1512 // victim's damage shield
1513 std::set<Aura*> alreadyDone;
1514 uint32 removedAuras = pVictim->m_removedAuras;
1515 AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
1516 for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
1518 next++;
1519 if (alreadyDone.find(*i) == alreadyDone.end())
1521 alreadyDone.insert(*i);
1522 uint32 damage=(*i)->GetModifier()->m_amount;
1523 SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId());
1524 if(!spellProto)
1525 continue;
1526 //Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist?
1527 //uint32 absorb;
1528 //uint32 resist;
1529 //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
1530 //damage-=absorb + resist;
1532 pVictim->DealDamageMods(this,damage,NULL);
1534 WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4));
1535 data << uint64(pVictim->GetGUID());
1536 data << uint64(GetGUID());
1537 data << uint32(spellProto->Id);
1538 data << uint32(damage); // Damage
1539 data << uint32(0); // Overkill
1540 data << uint32(spellProto->SchoolMask);
1541 pVictim->SendMessageToSet(&data, true );
1543 pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
1545 if (pVictim->m_removedAuras > removedAuras)
1547 removedAuras = pVictim->m_removedAuras;
1548 next = vDamageShields.begin();
1556 void Unit::HandleEmoteCommand(uint32 anim_id)
1558 WorldPacket data( SMSG_EMOTE, 4 + 8 );
1559 data << uint32(anim_id);
1560 data << uint64(GetGUID());
1561 SendMessageToSet(&data, true);
1564 uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage)
1566 uint32 newdamage = 0;
1567 float armor = pVictim->GetArmor();
1568 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1569 armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
1571 // Apply Player CR_ARMOR_PENETRATION rating
1572 if (GetTypeId()==TYPEID_PLAYER)
1573 armor *= 1.0f - ((Player*)this)->GetRatingBonusValue(CR_ARMOR_PENETRATION) / 100.0f;
1575 if (armor < 0.0f) armor=0.0f;
1577 float levelModifier = getLevel();
1578 if ( levelModifier > 59 )
1579 levelModifier = levelModifier + (4.5f * (levelModifier-59));
1581 float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40);
1582 tmpvalue = tmpvalue/(1.0f + tmpvalue);
1584 if(tmpvalue < 0.0f)
1585 tmpvalue = 0.0f;
1586 if(tmpvalue > 0.75f)
1587 tmpvalue = 0.75f;
1588 newdamage = uint32(damage - (damage * tmpvalue));
1590 return (newdamage > 1) ? newdamage : 1;
1593 void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist)
1595 if(!pVictim || !pVictim->isAlive() || !damage)
1596 return;
1598 // Magic damage, check for resists
1599 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL)==0)
1601 // Get base victim resistance for school
1602 float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask));
1603 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1604 tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
1606 tmpvalue2 *= (float)(0.15f / getLevel());
1607 if (tmpvalue2 < 0.0f)
1608 tmpvalue2 = 0.0f;
1609 if (tmpvalue2 > 0.75f)
1610 tmpvalue2 = 0.75f;
1611 uint32 ran = urand(0, 100);
1612 uint32 faq[4] = {24,6,4,6};
1613 uint8 m = 0;
1614 float Binom = 0.0f;
1615 for (uint8 i = 0; i < 4; ++i)
1617 Binom += 2400 *( powf(tmpvalue2, i) * powf( (1-tmpvalue2), (4-i)))/faq[i];
1618 if (ran > Binom )
1619 ++m;
1620 else
1621 break;
1623 if (damagetype == DOT && m == 4)
1624 *resist += uint32(damage - 1);
1625 else
1626 *resist += uint32(damage * m / 4);
1627 if(*resist > damage)
1628 *resist = damage;
1630 else
1631 *resist = 0;
1633 int32 RemainingDamage = damage - *resist;
1635 // Get unit state (need for some absorb check)
1636 uint32 unitflag = pVictim->GetUInt32Value(UNIT_FIELD_FLAGS);
1637 // Reflect damage spells (not cast any damage spell in aura lookup)
1638 uint32 reflectSpell = 0;
1639 int32 reflectDamage = 0;
1640 // Death Prevention Aura
1641 SpellEntry const* preventDeathSpell = NULL;
1642 int32 preventDeathAmount = 0;
1643 // Need remove expired auras after
1644 bool existExpired = false;
1645 // absorb without mana cost
1646 AuraList const& vSchoolAbsorb = pVictim->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB);
1647 for(AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i)
1649 Modifier* mod = (*i)->GetModifier();
1650 if (!(mod->m_miscvalue & schoolMask))
1651 continue;
1653 SpellEntry const* spellProto = (*i)->GetSpellProto();
1655 // Max Amount can be absorbed by this aura
1656 int32 currentAbsorb = mod->m_amount;
1658 // Found empty aura (impossible but..)
1659 if (currentAbsorb <=0)
1661 existExpired = true;
1662 continue;
1664 // Handle custom absorb auras
1665 // TODO: try find better way
1666 switch(spellProto->SpellFamilyName)
1668 case SPELLFAMILY_GENERIC:
1670 // Astral Shift
1671 if (spellProto->SpellIconID == 3066)
1673 //reduces all damage taken while stun, fear or silence
1674 if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))
1675 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1676 continue;
1678 // Nerves of Steel
1679 if (spellProto->SpellIconID == 2115)
1681 // while affected by Stun and Fear
1682 if (unitflag&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING))
1683 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1684 continue;
1686 // Spell Deflection
1687 if (spellProto->SpellIconID == 3006)
1689 // You have a chance equal to your Parry chance
1690 if (damagetype == DIRECT_DAMAGE && // Only for direct damage
1691 roll_chance_f(pVictim->GetUnitParryChance())) // Roll chance
1692 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1693 continue;
1695 // Reflective Shield (Lady Malande boss)
1696 if (spellProto->Id == 41475)
1698 if(RemainingDamage < currentAbsorb)
1699 reflectDamage = RemainingDamage / 2;
1700 else
1701 reflectDamage = currentAbsorb / 2;
1702 reflectSpell = 33619;
1703 break;
1705 if (spellProto->Id == 39228 || // Argussian Compass
1706 spellProto->Id == 60218) // Essence of Gossamer
1708 // Max absorb stored in 1 dummy effect
1709 if (spellProto->EffectBasePoints[1] < currentAbsorb)
1710 currentAbsorb = spellProto->EffectBasePoints[1];
1711 break;
1713 break;
1715 case SPELLFAMILY_DRUID:
1717 // Primal Tenacity
1718 if (spellProto->SpellIconID == 2253)
1720 //reduces all damage taken while Stunned
1721 if (unitflag & UNIT_FLAG_STUNNED)
1722 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1723 continue;
1725 break;
1727 case SPELLFAMILY_ROGUE:
1729 // Cheat Death (make less prio with Guardian Spirit case)
1730 if (!preventDeathSpell && spellProto->SpellIconID == 2109 &&
1731 pVictim->GetTypeId()==TYPEID_PLAYER && // Only players
1732 !((Player*)pVictim)->HasSpellCooldown(31231) &&
1733 // Only if no cooldown
1734 roll_chance_i((*i)->GetModifier()->m_amount))
1735 // Only if roll
1737 preventDeathSpell = (*i)->GetSpellProto();
1738 continue;
1740 break;
1742 case SPELLFAMILY_PRIEST:
1744 // Guardian Spirit
1745 if (spellProto->SpellIconID == 2873)
1747 preventDeathSpell = (*i)->GetSpellProto();
1748 preventDeathAmount = (*i)->GetModifier()->m_amount;
1749 continue;
1752 // Reflective Shield
1753 if (spellProto->SpellFamilyFlags == 0x1)
1755 if (pVictim == this)
1756 break;
1757 Unit* caster = (*i)->GetCaster();
1758 if (!caster)
1759 break;
1760 AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY);
1761 for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k)
1763 switch((*k)->GetModifier()->m_miscvalue)
1765 case 5065: // Rank 1
1766 case 5064: // Rank 2
1767 case 5063: // Rank 3
1769 if(RemainingDamage >= currentAbsorb)
1770 reflectDamage = (*k)->GetModifier()->m_amount * currentAbsorb/100;
1771 else
1772 reflectDamage = (*k)->GetModifier()->m_amount * RemainingDamage/100;
1773 reflectSpell = 33619;
1774 } break;
1775 default: break;
1778 break;
1780 break;
1782 case SPELLFAMILY_SHAMAN:
1784 // Astral Shift
1785 if (spellProto->SpellIconID == 3066)
1787 //reduces all damage taken while stun, fear or silence
1788 if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))
1789 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1790 continue;
1792 break;
1794 case SPELLFAMILY_DEATHKNIGHT:
1796 // Shadow of Death
1797 if (spellProto->SpellIconID == 1958)
1799 // TODO: absorb only while transform
1800 continue;
1802 // Anti-Magic Shell (on self)
1803 if (spellProto->Id == 48707)
1805 // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power.
1806 // This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power.
1807 int32 absorbed = RemainingDamage * currentAbsorb / 100;
1808 int32 regen = absorbed * 2 / 10;
1809 pVictim->CastCustomSpell(pVictim, 49088, &regen, NULL, NULL, true, NULL, *i);
1810 RemainingDamage -= absorbed;
1811 continue;
1813 // Anti-Magic Shell (on single party/raid member)
1814 if (spellProto->Id == 50462)
1816 RemainingDamage -= RemainingDamage * currentAbsorb / 100;
1817 continue;
1819 // Anti-Magic Zone
1820 if (spellProto->Id == 50461)
1822 Unit* caster = (*i)->GetCaster();
1823 if (!caster)
1824 continue;
1825 int32 absorbed = RemainingDamage * currentAbsorb / 100;
1826 int32 canabsorb = caster->GetHealth();
1827 if (canabsorb < absorbed)
1828 absorbed = canabsorb;
1830 RemainingDamage -= absorbed;
1832 uint32 ab_damage = absorbed;
1833 DealDamageMods(caster,ab_damage,NULL);
1834 DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false);
1835 continue;
1837 break;
1839 default:
1840 break;
1843 // currentAbsorb - damage can be absorbed by shield
1844 // If need absorb less damage
1845 if (RemainingDamage < currentAbsorb)
1846 currentAbsorb = RemainingDamage;
1848 RemainingDamage -= currentAbsorb;
1850 // Reduce shield amount
1851 mod->m_amount-=currentAbsorb;
1852 // Need remove it later
1853 if (mod->m_amount<=0)
1854 existExpired = true;
1857 // Remove all expired absorb auras
1858 if (existExpired)
1860 for(AuraList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();)
1862 if ((*i)->GetModifier()->m_amount<=0)
1864 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1865 i = vSchoolAbsorb.begin();
1867 else
1868 ++i;
1872 // Cast back reflect damage spell
1873 if (reflectSpell)
1874 pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true);
1876 // absorb by mana cost
1877 AuraList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
1878 for(AuraList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next)
1880 next = i; ++next;
1882 // check damage school mask
1883 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1884 continue;
1886 int32 currentAbsorb;
1887 if (RemainingDamage >= (*i)->GetModifier()->m_amount)
1888 currentAbsorb = (*i)->GetModifier()->m_amount;
1889 else
1890 currentAbsorb = RemainingDamage;
1892 float manaMultiplier = (*i)->GetSpellProto()->EffectMultipleValue[(*i)->GetEffIndex()];
1893 if(Player *modOwner = pVictim->GetSpellModOwner())
1894 modOwner->ApplySpellMod((*i)->GetId(), SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
1896 int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
1897 if (currentAbsorb > maxAbsorb)
1898 currentAbsorb = maxAbsorb;
1900 (*i)->GetModifier()->m_amount -= currentAbsorb;
1901 if((*i)->GetModifier()->m_amount <= 0)
1903 pVictim->RemoveAurasDueToSpell((*i)->GetId());
1904 next = vManaShield.begin();
1907 int32 manaReduction = int32(currentAbsorb * manaMultiplier);
1908 pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
1910 RemainingDamage -= currentAbsorb;
1913 // only split damage if not damaging yourself
1914 if(pVictim != this)
1916 AuraList const& vSplitDamageFlat = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT);
1917 for(AuraList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next)
1919 next = i; ++next;
1921 // check damage school mask
1922 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1923 continue;
1925 // Damage can be splitted only if aura has an alive caster
1926 Unit *caster = (*i)->GetCaster();
1927 if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
1928 continue;
1930 int32 currentAbsorb;
1931 if (RemainingDamage >= (*i)->GetModifier()->m_amount)
1932 currentAbsorb = (*i)->GetModifier()->m_amount;
1933 else
1934 currentAbsorb = RemainingDamage;
1936 RemainingDamage -= currentAbsorb;
1939 uint32 splitted = currentAbsorb;
1940 uint32 splitted_absorb = 0;
1941 DealDamageMods(caster,splitted,&splitted_absorb);
1943 SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
1945 CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
1946 DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
1949 AuraList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
1950 for(AuraList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next)
1952 next = i; ++next;
1954 // check damage school mask
1955 if(((*i)->GetModifier()->m_miscvalue & schoolMask)==0)
1956 continue;
1958 // Damage can be splitted only if aura has an alive caster
1959 Unit *caster = (*i)->GetCaster();
1960 if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
1961 continue;
1963 uint32 splitted = uint32(RemainingDamage * (*i)->GetModifier()->m_amount / 100.0f);
1965 RemainingDamage -= int32(splitted);
1967 uint32 split_absorb = 0;
1968 DealDamageMods(caster,splitted,&split_absorb);
1970 SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
1972 CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
1973 DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
1977 // Apply death prevention spells effects
1978 if (preventDeathSpell && RemainingDamage >= pVictim->GetHealth())
1980 switch(preventDeathSpell->SpellFamilyName)
1982 // Cheat Death
1983 case SPELLFAMILY_ROGUE:
1985 // Cheat Death
1986 if (preventDeathSpell->SpellIconID == 2109)
1988 pVictim->CastSpell(pVictim,31231,true);
1989 ((Player*)pVictim)->AddSpellCooldown(31231,0,time(NULL)+60);
1990 // with health > 10% lost health until health==10%, in other case no losses
1991 uint32 health10 = pVictim->GetMaxHealth()/10;
1992 RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0;
1994 break;
1996 // Guardian Spirit
1997 case SPELLFAMILY_PRIEST:
1999 // Guardian Spirit
2000 if (preventDeathSpell->SpellIconID == 2873)
2002 int32 healAmount = pVictim->GetMaxHealth() * preventDeathAmount / 100;
2003 pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true);
2004 pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id);
2005 RemainingDamage = 0;
2007 break;
2012 *absorb = damage - RemainingDamage - *resist;
2015 void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
2017 if(hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
2018 return;
2020 if (!pVictim->isAlive())
2021 return;
2023 if(IsNonMeleeSpellCasted(false))
2024 return;
2026 uint32 hitInfo;
2027 if (attType == BASE_ATTACK)
2028 hitInfo = HITINFO_NORMALSWING2;
2029 else if (attType == OFF_ATTACK)
2030 hitInfo = HITINFO_LEFTSWING;
2031 else
2032 return; // ignore ranged case
2034 uint32 extraAttacks = m_extraAttacks;
2036 // melee attack spell casted at main hand attack only
2037 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL])
2039 m_currentSpells[CURRENT_MELEE_SPELL]->cast();
2041 // not recent extra attack only at any non extra attack (melee spell case)
2042 if(!extra && extraAttacks)
2044 while(m_extraAttacks)
2046 AttackerStateUpdate(pVictim, BASE_ATTACK, true);
2047 if(m_extraAttacks > 0)
2048 --m_extraAttacks;
2051 return;
2054 // attack can be redirected to another target
2055 pVictim = SelectMagnetTarget(pVictim);
2057 CalcDamageInfo damageInfo;
2058 CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
2059 // Send log damage message to client
2060 DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb);
2061 SendAttackStateUpdate(&damageInfo);
2062 ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
2063 DealMeleeDamage(&damageInfo,true);
2065 if (GetTypeId() == TYPEID_PLAYER)
2066 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2067 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
2068 else
2069 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2070 GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
2072 // if damage pVictim call AI reaction
2073 if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->AI())
2074 ((Creature*)pVictim)->AI()->AttackedBy(this);
2076 // extra attack only at any non extra attack (normal case)
2077 if(!extra && extraAttacks)
2079 while(m_extraAttacks)
2081 AttackerStateUpdate(pVictim, BASE_ATTACK, true);
2082 if(m_extraAttacks > 0)
2083 --m_extraAttacks;
2088 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const
2090 // This is only wrapper
2092 // Miss chance based on melee
2093 float miss_chance = MeleeMissChanceCalc(pVictim, attType);
2095 // Critical hit chance
2096 float crit_chance = GetUnitCriticalChance(attType, pVictim);
2098 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2099 float dodge_chance = pVictim->GetUnitDodgeChance();
2100 float block_chance = pVictim->GetUnitBlockChance();
2101 float parry_chance = pVictim->GetUnitParryChance();
2103 // Useful if want to specify crit & miss chances for melee, else it could be removed
2104 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance,crit_chance,dodge_chance,parry_chance,block_chance);
2106 return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100));
2109 MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
2111 if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
2112 return MELEE_HIT_EVADE;
2114 int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(pVictim);
2115 int32 victimMaxSkillValueForLevel = pVictim->GetMaxSkillValueForLevel(this);
2117 int32 attackerWeaponSkill = GetWeaponSkillValue(attType,pVictim);
2118 int32 victimDefenseSkill = pVictim->GetDefenseSkillValue(this);
2120 // bonus from skills is 0.04%
2121 int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel );
2122 int32 sum = 0, tmp = 0;
2123 int32 roll = urand (0, 10000);
2125 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
2126 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2127 roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
2129 tmp = miss_chance;
2131 if (tmp > 0 && roll < (sum += tmp ))
2133 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2134 return MELEE_HIT_MISS;
2137 // always crit against a sitting target (except 0 crit chance)
2138 if( pVictim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !pVictim->IsStandState() )
2140 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2141 return MELEE_HIT_CRIT;
2144 // Dodge chance
2146 // only players can't dodge if attacker is behind
2147 if (pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasInArc(M_PI,this))
2149 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2151 else
2153 // Reduce dodge chance by attacker expertise rating
2154 if (GetTypeId() == TYPEID_PLAYER)
2155 dodge_chance -= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100);
2157 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2158 dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2160 tmp = dodge_chance;
2161 if ( (tmp > 0) // check if unit _can_ dodge
2162 && ((tmp -= skillBonus) > 0)
2163 && roll < (sum += tmp))
2165 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
2166 return MELEE_HIT_DODGE;
2170 // parry & block chances
2172 // check if attack comes from behind, nobody can parry or block if attacker is behind
2173 if (!pVictim->HasInArc(M_PI,this))
2175 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2177 else
2179 // Reduce parry chance by attacker expertise rating
2180 if (GetTypeId() == TYPEID_PLAYER)
2181 parry_chance-= int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType)*100);
2183 if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY) )
2185 int32 tmp2 = int32(parry_chance);
2186 if ( (tmp2 > 0) // check if unit _can_ parry
2187 && ((tmp2 -= skillBonus) > 0)
2188 && (roll < (sum += tmp2)))
2190 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum);
2191 return MELEE_HIT_PARRY;
2195 if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK) )
2197 tmp = block_chance;
2198 if ( (tmp > 0) // check if unit _can_ block
2199 && ((tmp -= skillBonus) > 0)
2200 && (roll < (sum += tmp)))
2202 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
2203 return MELEE_HIT_BLOCK;
2208 // Critical chance
2209 tmp = crit_chance;
2211 if (tmp > 0 && roll < (sum += tmp))
2213 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
2214 return MELEE_HIT_CRIT;
2217 // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
2218 if( attType != RANGED_ATTACK &&
2219 (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) &&
2220 pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() &&
2221 getLevel() < pVictim->getLevelForTarget(this) )
2223 // cap possible value (with bonuses > max skill)
2224 int32 skill = attackerWeaponSkill;
2225 int32 maxskill = attackerMaxSkillValueForLevel;
2226 skill = (skill > maxskill) ? maxskill : skill;
2228 tmp = (10 + (victimDefenseSkill - skill)) * 100;
2229 tmp = tmp > 4000 ? 4000 : tmp;
2230 if (roll < (sum += tmp))
2232 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
2233 return MELEE_HIT_GLANCING;
2237 // mobs can score crushing blows if they're 4 or more levels above victim
2238 if (getLevelForTarget(pVictim) >= pVictim->getLevelForTarget(this) + 4 &&
2239 // can be from by creature (if can) or from controlled player that considered as creature
2240 (GetTypeId()!=TYPEID_PLAYER && !((Creature*)this)->isPet() &&
2241 !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) ||
2242 GetTypeId()==TYPEID_PLAYER && GetCharmerOrOwnerGUID()))
2244 // when their weapon skill is 15 or more above victim's defense skill
2245 tmp = victimDefenseSkill;
2246 int32 tmpmax = victimMaxSkillValueForLevel;
2247 // having defense above your maximum (from items, talents etc.) has no effect
2248 tmp = tmp > tmpmax ? tmpmax : tmp;
2249 // tmp = mob's level * 5 - player's current defense skill
2250 tmp = attackerMaxSkillValueForLevel - tmp;
2251 if(tmp >= 15)
2253 // add 2% chance per lacking skill point, min. is 15%
2254 tmp = tmp * 200 - 1500;
2255 if (roll < (sum += tmp))
2257 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
2258 return MELEE_HIT_CRUSHING;
2263 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2264 return MELEE_HIT_NORMAL;
2267 uint32 Unit::CalculateDamage (WeaponAttackType attType, bool normalized)
2269 float min_damage, max_damage;
2271 if (normalized && GetTypeId()==TYPEID_PLAYER)
2272 ((Player*)this)->CalculateMinMaxDamage(attType,normalized,min_damage, max_damage);
2273 else
2275 switch (attType)
2277 case RANGED_ATTACK:
2278 min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
2279 max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
2280 break;
2281 case BASE_ATTACK:
2282 min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
2283 max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
2284 break;
2285 case OFF_ATTACK:
2286 min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
2287 max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
2288 break;
2289 // Just for good manner
2290 default:
2291 min_damage = 0.0f;
2292 max_damage = 0.0f;
2293 break;
2297 if (min_damage > max_damage)
2299 std::swap(min_damage,max_damage);
2302 if(max_damage == 0.0f)
2303 max_damage = 5.0f;
2305 return urand((uint32)min_damage, (uint32)max_damage);
2308 float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const
2310 if(spellProto->spellLevel <= 0)
2311 return 1.0f;
2313 float LvlPenalty = 0.0f;
2315 if(spellProto->spellLevel < 20)
2316 LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f;
2317 float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel());
2318 if(LvlFactor > 1.0f)
2319 LvlFactor = 1.0f;
2321 return (100.0f - LvlPenalty) * LvlFactor / 100.0f;
2324 void Unit::SendMeleeAttackStart(Unit* pVictim)
2326 WorldPacket data( SMSG_ATTACKSTART, 8 + 8 );
2327 data << uint64(GetGUID());
2328 data << uint64(pVictim->GetGUID());
2330 SendMessageToSet(&data, true);
2331 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2334 void Unit::SendMeleeAttackStop(Unit* victim)
2336 if(!victim)
2337 return;
2339 WorldPacket data( SMSG_ATTACKSTOP, (4+16) ); // we guess size
2340 data.append(GetPackGUID());
2341 data.append(victim->GetPackGUID()); // can be 0x00...
2342 data << uint32(0); // can be 0x1
2343 SendMessageToSet(&data, true);
2344 sLog.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (victim->GetTypeId()==TYPEID_PLAYER ? "player" : "creature"),victim->GetGUIDLow());
2346 /*if(victim->GetTypeId() == TYPEID_UNIT)
2347 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2350 bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const * /*spellProto*/, WeaponAttackType attackType)
2352 if (pVictim->HasInArc(M_PI,this))
2354 /* Currently not exist spells with ignore block
2355 // Ignore combat result aura (parry/dodge check on prepare)
2356 AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2357 for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
2359 if (!(*i)->isAffectedOnSpell(spellProto))
2360 continue;
2361 if ((*i)->GetModifier()->m_miscvalue == )
2362 return false;
2366 // Check creatures flags_extra for disable block
2367 if(pVictim->GetTypeId()==TYPEID_UNIT &&
2368 ((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK )
2369 return false;
2371 float blockChance = pVictim->GetUnitBlockChance();
2372 blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(pVictim->GetMaxSkillValueForLevel()))*0.04f;
2373 if (roll_chance_f(blockChance))
2374 return true;
2376 return false;
2379 // Melee based spells can be miss, parry or dodge on this step
2380 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2381 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2383 // Calculate hit chance (more correct for chance mod)
2384 int32 HitChance;
2386 // PvP - PvE melee chances
2387 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2388 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2389 if(leveldif < 3)
2390 HitChance = 95 - leveldif;
2391 else
2392 HitChance = 93 - (leveldif - 2) * lchance;
2394 // Hit chance depends from victim auras
2395 if(attType == RANGED_ATTACK)
2396 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2397 else
2398 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2400 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2401 if(Player *modOwner = GetSpellModOwner())
2402 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2404 // Miss = 100 - hit
2405 float miss_chance= 100.0f - HitChance;
2407 // Bonuses from attacker aura and ratings
2408 if (attType == RANGED_ATTACK)
2409 miss_chance -= m_modRangedHitChance;
2410 else
2411 miss_chance -= m_modMeleeHitChance;
2413 // bonus from skills is 0.04%
2414 miss_chance -= skillDiff * 0.04f;
2416 // Limit miss chance from 0 to 60%
2417 if (miss_chance < 0.0f)
2418 return 0.0f;
2419 if (miss_chance > 60.0f)
2420 return 60.0f;
2421 return miss_chance;
2424 // Melee based spells hit result calculations
2425 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2427 WeaponAttackType attType = BASE_ATTACK;
2429 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2430 attType = RANGED_ATTACK;
2432 // bonus from skills is 0.04% per skill Diff
2433 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2434 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2435 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2437 uint32 roll = urand (0, 10000);
2439 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2440 // Roll miss
2441 uint32 tmp = missChance;
2442 if (roll < tmp)
2443 return SPELL_MISS_MISS;
2445 // Chance resist mechanic (select max value from every mechanic spell effect)
2446 int32 resist_mech = 0;
2447 // Get effects mechanic and chance
2448 for(int eff = 0; eff < 3; ++eff)
2450 int32 effect_mech = GetEffectMechanic(spell, eff);
2451 if (effect_mech)
2453 int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
2454 if (resist_mech < temp*100)
2455 resist_mech = temp*100;
2458 // Roll chance
2459 tmp += resist_mech;
2460 if (roll < tmp)
2461 return SPELL_MISS_RESIST;
2463 bool canDodge = true;
2464 bool canParry = true;
2466 // Same spells cannot be parry/dodge
2467 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2468 return SPELL_MISS_NONE;
2470 // Ranged attack cannot be parry/dodge only deflect
2471 if (attType == RANGED_ATTACK)
2473 // only if in front
2474 if (pVictim->HasInArc(M_PI,this))
2476 int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS)*100;
2477 tmp+=deflect_chance;
2478 if (roll < tmp)
2479 return SPELL_MISS_DEFLECT;
2481 return SPELL_MISS_NONE;
2484 // Check for attack from behind
2485 if (!pVictim->HasInArc(M_PI,this))
2487 // Can`t dodge from behind in PvP (but its possible in PvE)
2488 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
2489 canDodge = false;
2490 // Can`t parry
2491 canParry = false;
2493 // Check creatures flags_extra for disable parry
2494 if(pVictim->GetTypeId()==TYPEID_UNIT)
2496 uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra;
2497 if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY )
2498 canParry = false;
2500 // Ignore combat result aura
2501 AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2502 for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
2504 if (!(*i)->isAffectedOnSpell(spell))
2505 continue;
2506 switch((*i)->GetModifier()->m_miscvalue)
2508 case MELEE_HIT_DODGE: canDodge = false; break;
2509 case MELEE_HIT_BLOCK: break; // Block check in hit step
2510 case MELEE_HIT_PARRY: canParry = false; break;
2511 default:
2512 DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue);
2513 break;
2517 if (canDodge)
2519 // Roll dodge
2520 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2521 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2522 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE)*100;
2523 // Reduce dodge chance by attacker expertise rating
2524 if (GetTypeId() == TYPEID_PLAYER)
2525 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2526 if (dodgeChance < 0)
2527 dodgeChance = 0;
2529 tmp += dodgeChance;
2530 if (roll < tmp)
2531 return SPELL_MISS_DODGE;
2534 if (canParry)
2536 // Roll parry
2537 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2538 // Reduce parry chance by attacker expertise rating
2539 if (GetTypeId() == TYPEID_PLAYER)
2540 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2541 if (parryChance < 0)
2542 parryChance = 0;
2544 tmp += parryChance;
2545 if (roll < tmp)
2546 return SPELL_MISS_PARRY;
2549 return SPELL_MISS_NONE;
2552 // TODO need use unit spell resistances in calculations
2553 SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2555 // Can`t miss on dead target (on skinning for example)
2556 if (!pVictim->isAlive())
2557 return SPELL_MISS_NONE;
2559 SpellSchoolMask schoolMask = GetSpellSchoolMask(spell);
2560 // PvP - PvE spell misschances per leveldif > 2
2561 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
2562 int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim));
2564 // Base hit chance from attacker and victim levels
2565 int32 modHitChance;
2566 if(leveldif < 3)
2567 modHitChance = 96 - leveldif;
2568 else
2569 modHitChance = 94 - (leveldif - 2) * lchance;
2571 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2572 if(Player *modOwner = GetSpellModOwner())
2573 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
2574 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2575 modHitChance+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
2576 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2577 modHitChance+= pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
2578 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2579 if (IsAreaOfEffectSpell(spell))
2580 modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
2581 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2582 if (IsDispelSpell(spell))
2583 modHitChance-=pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST);
2584 // Chance resist mechanic (select max value from every mechanic spell effect)
2585 int32 resist_mech = 0;
2586 // Get effects mechanic and chance
2587 for(int eff = 0; eff < 3; ++eff)
2589 int32 effect_mech = GetEffectMechanic(spell, eff);
2590 if (effect_mech)
2592 int32 temp = pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
2593 if (resist_mech < temp)
2594 resist_mech = temp;
2597 // Apply mod
2598 modHitChance-=resist_mech;
2600 // Chance resist debuff
2601 modHitChance-=pVictim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel));
2603 int32 HitChance = modHitChance * 100;
2604 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2605 HitChance += int32(m_modSpellHitChance*100.0f);
2607 // Decrease hit chance from victim rating bonus
2608 if (pVictim->GetTypeId()==TYPEID_PLAYER)
2609 HitChance -= int32(((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL)*100.0f);
2611 if (HitChance < 100) HitChance = 100;
2612 if (HitChance > 10000) HitChance = 10000;
2614 int32 tmp = 10000 - HitChance;
2616 uint32 rand = urand(0,10000);
2618 if (rand < tmp)
2619 return SPELL_MISS_RESIST;
2621 // cast by caster in front of victim
2622 if (pVictim->HasInArc(M_PI,this))
2624 int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS)*100;
2625 tmp+=deflect_chance;
2626 if (rand < tmp)
2627 return SPELL_MISS_DEFLECT;
2630 return SPELL_MISS_NONE;
2633 // Calculate spell hit result can be:
2634 // Every spell can: Evade/Immune/Reflect/Sucesful hit
2635 // For melee based spells:
2636 // Miss
2637 // Dodge
2638 // Parry
2639 // For spells
2640 // Resist
2641 SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect)
2643 // Return evade for units in evade mode
2644 if (pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
2645 return SPELL_MISS_EVADE;
2647 // Check for immune
2648 if (pVictim->IsImmunedToSpell(spell))
2649 return SPELL_MISS_IMMUNE;
2651 // All positive spells can`t miss
2652 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2653 if (IsPositiveSpell(spell->Id))
2654 return SPELL_MISS_NONE;
2656 // Check for immune
2657 if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell)))
2658 return SPELL_MISS_IMMUNE;
2660 // Try victim reflect spell
2661 if (CanReflect)
2663 int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
2664 Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
2665 for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
2666 if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
2667 reflectchance += (*i)->GetModifier()->m_amount;
2668 if (reflectchance > 0 && roll_chance_i(reflectchance))
2670 // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
2671 ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell);
2672 return SPELL_MISS_REFLECT;
2676 switch (spell->DmgClass)
2678 case SPELL_DAMAGE_CLASS_RANGED:
2679 case SPELL_DAMAGE_CLASS_MELEE:
2680 return MeleeSpellHitResult(pVictim, spell);
2681 case SPELL_DAMAGE_CLASS_NONE:
2682 case SPELL_DAMAGE_CLASS_MAGIC:
2683 return MagicSpellHitResult(pVictim, spell);
2685 return SPELL_MISS_NONE;
2688 float Unit::MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const
2690 if(!pVictim)
2691 return 0.0f;
2693 // Base misschance 5%
2694 float misschance = 5.0f;
2696 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2697 if (haveOffhandWeapon() && attType != RANGED_ATTACK)
2699 bool isNormal = false;
2700 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
2702 if( m_currentSpells[i] && (GetSpellSchoolMask(m_currentSpells[i]->m_spellInfo) & SPELL_SCHOOL_MASK_NORMAL) )
2704 isNormal = true;
2705 break;
2708 if (isNormal || m_currentSpells[CURRENT_MELEE_SPELL])
2710 misschance = 5.0f;
2712 else
2714 misschance = 24.0f;
2718 // PvP : PvE melee misschances per leveldif > 2
2719 int32 chance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2721 int32 leveldif = int32(pVictim->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim));
2722 if(leveldif < 0)
2723 leveldif = 0;
2725 // Hit chance from attacker based on ratings and auras
2726 float m_modHitChance;
2727 if (attType == RANGED_ATTACK)
2728 m_modHitChance = m_modRangedHitChance;
2729 else
2730 m_modHitChance = m_modMeleeHitChance;
2732 if(leveldif < 3)
2733 misschance += (leveldif - m_modHitChance);
2734 else
2735 misschance += ((leveldif - 2) * chance - m_modHitChance);
2737 // Hit chance for victim based on ratings
2738 if (pVictim->GetTypeId()==TYPEID_PLAYER)
2740 if (attType == RANGED_ATTACK)
2741 misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED);
2742 else
2743 misschance += ((Player*)pVictim)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE);
2746 // Modify miss chance by victim auras
2747 if(attType == RANGED_ATTACK)
2748 misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2749 else
2750 misschance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2752 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2753 int32 skillBonus = int32(GetWeaponSkillValue(attType,pVictim)) - int32(pVictim->GetDefenseSkillValue(this));
2754 misschance -= skillBonus * 0.04f;
2756 // Limit miss chance from 0 to 60%
2757 if ( misschance < 0.0f)
2758 return 0.0f;
2759 if ( misschance > 60.0f)
2760 return 60.0f;
2762 return misschance;
2765 uint32 Unit::GetDefenseSkillValue(Unit const* target) const
2767 if(GetTypeId() == TYPEID_PLAYER)
2769 // in PvP use full skill instead current skill value
2770 uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
2771 ? ((Player*)this)->GetMaxSkillValue(SKILL_DEFENSE)
2772 : ((Player*)this)->GetSkillValue(SKILL_DEFENSE);
2773 value += uint32(((Player*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL));
2774 return value;
2776 else
2777 return GetUnitMeleeSkill(target);
2780 float Unit::GetUnitDodgeChance() const
2782 if(hasUnitState(UNIT_STAT_STUNNED))
2783 return 0.0f;
2784 if( GetTypeId() == TYPEID_PLAYER )
2785 return GetFloatValue(PLAYER_DODGE_PERCENTAGE);
2786 else
2788 if(((Creature const*)this)->isTotem())
2789 return 0.0f;
2790 else
2792 float dodge = 5.0f;
2793 dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
2794 return dodge > 0.0f ? dodge : 0.0f;
2799 float Unit::GetUnitParryChance() const
2801 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED))
2802 return 0.0f;
2804 float chance = 0.0f;
2806 if(GetTypeId() == TYPEID_PLAYER)
2808 Player const* player = (Player const*)this;
2809 if(player->CanParry() )
2811 Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true);
2812 if(!tmpitem)
2813 tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true);
2815 if(tmpitem)
2816 chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2819 else if(GetTypeId() == TYPEID_UNIT)
2821 if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
2823 chance = 5.0f;
2824 chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
2828 return chance > 0.0f ? chance : 0.0f;
2831 float Unit::GetUnitBlockChance() const
2833 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED))
2834 return 0.0f;
2836 if(GetTypeId() == TYPEID_PLAYER)
2838 Player const* player = (Player const*)this;
2839 if(player->CanBlock() )
2841 Item *tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2842 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block)
2843 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2845 // is player but has no block ability or no not broken shield equipped
2846 return 0.0f;
2848 else
2850 if(((Creature const*)this)->isTotem())
2851 return 0.0f;
2852 else
2854 float block = 5.0f;
2855 block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
2856 return block > 0.0f ? block : 0.0f;
2861 float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVictim) const
2863 float crit;
2865 if(GetTypeId() == TYPEID_PLAYER)
2867 switch(attackType)
2869 case BASE_ATTACK:
2870 crit = GetFloatValue( PLAYER_CRIT_PERCENTAGE );
2871 break;
2872 case OFF_ATTACK:
2873 crit = GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE );
2874 break;
2875 case RANGED_ATTACK:
2876 crit = GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE );
2877 break;
2878 // Just for good manner
2879 default:
2880 crit = 0.0f;
2881 break;
2884 else
2886 crit = 5.0f;
2887 crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT);
2890 // flat aura mods
2891 if(attackType == RANGED_ATTACK)
2892 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
2893 else
2894 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
2896 crit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
2898 // reduce crit chance from Rating for players
2899 if (pVictim->GetTypeId()==TYPEID_PLAYER)
2901 if (attackType==RANGED_ATTACK)
2902 crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED);
2903 else
2904 crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE);
2907 // Apply crit chance from defence skill
2908 crit += (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f;
2910 if (crit < 0.0f)
2911 crit = 0.0f;
2912 return crit;
2915 uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const
2917 uint32 value = 0;
2918 if(GetTypeId() == TYPEID_PLAYER)
2920 Item* item = ((Player*)this)->GetWeaponForAttack(attType,true);
2922 // feral or unarmed skill only for base attack
2923 if(attType != BASE_ATTACK && !item )
2924 return 0;
2926 if(IsInFeralForm())
2927 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
2929 // weapon skill or (unarmed for base attack)
2930 uint32 skill = item ? item->GetSkill() : SKILL_UNARMED;
2932 // in PvP use full skill instead current skill value
2933 value = (target && target->GetTypeId() == TYPEID_PLAYER)
2934 ? ((Player*)this)->GetMaxSkillValue(skill)
2935 : ((Player*)this)->GetSkillValue(skill);
2936 // Modify value from ratings
2937 value += uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL));
2938 switch (attType)
2940 case BASE_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));break;
2941 case OFF_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));break;
2942 case RANGED_ATTACK: value+=uint32(((Player*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));break;
2945 else
2946 value = GetUnitMeleeSkill(target);
2947 return value;
2950 void Unit::_UpdateSpells( uint32 time )
2952 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
2953 _UpdateAutoRepeatSpell();
2955 // remove finished spells from current pointers
2956 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
2958 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2960 m_currentSpells[i]->SetReferencedFromCurrent(false);
2961 m_currentSpells[i] = NULL; // remove pointer
2965 // TODO: Find a better way to prevent crash when multiple auras are removed.
2966 m_removedAuras = 0;
2967 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
2968 if ((*i).second)
2969 (*i).second->SetUpdated(false);
2971 for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next)
2973 next = i;
2974 ++next;
2975 if ((*i).second)
2977 // prevent double update
2978 if ((*i).second->IsUpdated())
2979 continue;
2980 (*i).second->SetUpdated(true);
2981 (*i).second->Update( time );
2982 // several auras can be deleted due to update
2983 if (m_removedAuras)
2985 if (m_Auras.empty()) break;
2986 next = m_Auras.begin();
2987 m_removedAuras = 0;
2992 for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();)
2994 if ((*i).second)
2996 if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) )
2998 RemoveAura(i);
3000 else
3002 ++i;
3005 else
3007 ++i;
3011 if(!m_gameObj.empty())
3013 GameObjectList::iterator ite1, dnext1;
3014 for (ite1 = m_gameObj.begin(); ite1 != m_gameObj.end(); ite1 = dnext1)
3016 dnext1 = ite1;
3017 //(*i)->Update( difftime );
3018 if( !(*ite1)->isSpawned() )
3020 (*ite1)->SetOwnerGUID(0);
3021 (*ite1)->SetRespawnTime(0);
3022 (*ite1)->Delete();
3023 dnext1 = m_gameObj.erase(ite1);
3025 else
3026 ++dnext1;
3031 void Unit::_UpdateAutoRepeatSpell()
3033 //check "realtime" interrupts
3034 if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3036 // cancel wand shoot
3037 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
3038 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3039 m_AutoRepeatFirstCast = true;
3040 return;
3043 //apply delay
3044 if ( m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 )
3045 setAttackTimer(RANGED_ATTACK,500);
3046 m_AutoRepeatFirstCast = false;
3048 //castroutine
3049 if (isAttackReady(RANGED_ATTACK))
3051 // Check if able to cast
3052 if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
3054 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3055 return;
3058 // we want to shoot
3059 Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true, 0);
3060 spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
3062 // all went good, reset attack
3063 resetAttackTimer(RANGED_ATTACK);
3067 void Unit::SetCurrentCastedSpell( Spell * pSpell )
3069 assert(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3071 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
3073 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
3075 // break same type spell if it is not delayed
3076 InterruptSpell(CSpellType,false);
3078 // special breakage effects:
3079 switch (CSpellType)
3081 case CURRENT_GENERIC_SPELL:
3083 // generic spells always break channeled not delayed spells
3084 InterruptSpell(CURRENT_CHANNELED_SPELL,false);
3086 // autorepeat breaking
3087 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
3089 // break autorepeat if not Auto Shot
3090 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
3091 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3092 m_AutoRepeatFirstCast = true;
3094 } break;
3096 case CURRENT_CHANNELED_SPELL:
3098 // channel spells always break generic non-delayed and any channeled spells
3099 InterruptSpell(CURRENT_GENERIC_SPELL,false);
3100 InterruptSpell(CURRENT_CHANNELED_SPELL);
3102 // it also does break autorepeat if not Auto Shot
3103 if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
3104 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT )
3105 InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
3106 } break;
3108 case CURRENT_AUTOREPEAT_SPELL:
3110 // only Auto Shoot does not break anything
3111 if (pSpell->m_spellInfo->Id != SPELL_ID_AUTOSHOT)
3113 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3114 InterruptSpell(CURRENT_GENERIC_SPELL,false);
3115 InterruptSpell(CURRENT_CHANNELED_SPELL,false);
3117 // special action: set first cast flag
3118 m_AutoRepeatFirstCast = true;
3119 } break;
3121 default:
3123 // other spell types don't break anything now
3124 } break;
3127 // current spell (if it is still here) may be safely deleted now
3128 if (m_currentSpells[CSpellType])
3129 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3131 // set new current spell
3132 m_currentSpells[CSpellType] = pSpell;
3133 pSpell->SetReferencedFromCurrent(true);
3136 void Unit::InterruptSpell(uint32 spellType, bool withDelayed)
3138 assert(spellType < CURRENT_MAX_SPELL);
3140 if (m_currentSpells[spellType] && (withDelayed || m_currentSpells[spellType]->getState() != SPELL_STATE_DELAYED) )
3142 // send autorepeat cancel message for autorepeat spells
3143 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3145 if(GetTypeId()==TYPEID_PLAYER)
3146 ((Player*)this)->SendAutoRepeatCancel();
3149 if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
3150 m_currentSpells[spellType]->cancel();
3152 // cancel can interrupt spell already (caster cancel ->target aura remove -> caster iterrupt)
3153 if (m_currentSpells[spellType])
3155 m_currentSpells[spellType]->SetReferencedFromCurrent(false);
3156 m_currentSpells[spellType] = NULL;
3161 bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const
3163 // We don't do loop here to explicitly show that melee spell is excluded.
3164 // Maybe later some special spells will be excluded too.
3166 // generic spells are casted when they are not finished and not delayed
3167 if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
3168 (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
3169 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
3170 return(true);
3172 // channeled spells may be delayed, but they are still considered casted
3173 else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3174 (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
3175 return(true);
3177 // autorepeat spells may be finished or delayed, but they are still considered casted
3178 else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
3179 return(true);
3181 return(false);
3184 void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id)
3186 // generic spells are interrupted if they are not finished or delayed
3187 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id==spell_id))
3188 InterruptSpell(CURRENT_GENERIC_SPELL,withDelayed);
3190 // autorepeat spells are interrupted if they are not finished or delayed
3191 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id==spell_id))
3192 InterruptSpell(CURRENT_AUTOREPEAT_SPELL,withDelayed);
3194 // channeled spells are interrupted if they are not finished, even if they are delayed
3195 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id==spell_id))
3196 InterruptSpell(CURRENT_CHANNELED_SPELL,true);
3199 Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
3201 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
3202 if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id==spell_id)
3203 return m_currentSpells[i];
3204 return NULL;
3207 bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3209 return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
3212 void Unit::SetInFront(Unit const* target)
3214 SetOrientation(GetAngle(target));
3217 bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3219 return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target );
3222 bool Unit::isInAccessablePlaceFor(Creature const* c) const
3224 if(IsInWater())
3225 return c->canSwim();
3226 else
3227 return c->canWalk() || c->canFly();
3230 bool Unit::IsInWater() const
3232 return GetBaseMap()->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3235 bool Unit::IsUnderWater() const
3237 return GetBaseMap()->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3240 void Unit::DeMorph()
3242 SetDisplayId(GetNativeDisplayId());
3245 int32 Unit::GetTotalAuraModifier(AuraType auratype) const
3247 int32 modifier = 0;
3249 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3250 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3251 modifier += (*i)->GetModifier()->m_amount;
3253 return modifier;
3256 float Unit::GetTotalAuraMultiplier(AuraType auratype) const
3258 float multiplier = 1.0f;
3260 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3261 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3262 multiplier *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f;
3264 return multiplier;
3267 int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const
3269 int32 modifier = 0;
3271 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3272 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3273 if ((*i)->GetModifier()->m_amount > modifier)
3274 modifier = (*i)->GetModifier()->m_amount;
3276 return modifier;
3279 int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
3281 int32 modifier = 0;
3283 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3284 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3285 if ((*i)->GetModifier()->m_amount < modifier)
3286 modifier = (*i)->GetModifier()->m_amount;
3288 return modifier;
3291 int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3293 int32 modifier = 0;
3295 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3296 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3298 Modifier* mod = (*i)->GetModifier();
3299 if (mod->m_miscvalue & misc_mask)
3300 modifier += mod->m_amount;
3302 return modifier;
3305 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
3307 float multiplier = 1.0f;
3309 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3310 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3312 Modifier* mod = (*i)->GetModifier();
3313 if (mod->m_miscvalue & misc_mask)
3314 multiplier *= (100.0f + mod->m_amount)/100.0f;
3316 return multiplier;
3319 int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3321 int32 modifier = 0;
3323 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3324 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3326 Modifier* mod = (*i)->GetModifier();
3327 if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier)
3328 modifier = mod->m_amount;
3331 return modifier;
3334 int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
3336 int32 modifier = 0;
3338 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3339 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3341 Modifier* mod = (*i)->GetModifier();
3342 if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier)
3343 modifier = mod->m_amount;
3346 return modifier;
3349 int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3351 int32 modifier = 0;
3353 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3354 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3356 Modifier* mod = (*i)->GetModifier();
3357 if (mod->m_miscvalue == misc_value)
3358 modifier += mod->m_amount;
3360 return modifier;
3363 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
3365 float multiplier = 1.0f;
3367 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3368 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3370 Modifier* mod = (*i)->GetModifier();
3371 if (mod->m_miscvalue == misc_value)
3372 multiplier *= (100.0f + mod->m_amount)/100.0f;
3374 return multiplier;
3377 int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3379 int32 modifier = 0;
3381 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3382 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3384 Modifier* mod = (*i)->GetModifier();
3385 if (mod->m_miscvalue == misc_value && mod->m_amount > modifier)
3386 modifier = mod->m_amount;
3389 return modifier;
3392 int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
3394 int32 modifier = 0;
3396 AuraList const& mTotalAuraList = GetAurasByType(auratype);
3397 for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
3399 Modifier* mod = (*i)->GetModifier();
3400 if (mod->m_miscvalue == misc_value && mod->m_amount < modifier)
3401 modifier = mod->m_amount;
3404 return modifier;
3407 bool Unit::AddAura(Aura *Aur)
3409 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3410 if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
3411 (GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) )
3413 delete Aur;
3414 return false;
3417 if(Aur->GetTarget() != this)
3419 sLog.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3420 Aur->GetId(),Aur->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER?"player":"creature"),GetGUIDLow(),
3421 (Aur->GetTarget()->GetTypeId()==TYPEID_PLAYER?"player":"creature"),Aur->GetTarget()->GetGUIDLow());
3422 delete Aur;
3423 return false;
3426 SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
3427 AuraType aurName = Aur->GetModifier()->m_auraname;
3429 spellEffectPair spair = spellEffectPair(Aur->GetId(), Aur->GetEffIndex());
3430 AuraMap::iterator i = m_Auras.find( spair );
3432 // take out same spell
3433 if (i != m_Auras.end())
3435 // passive and persistent auras can stack with themselves any number of times
3436 if (!Aur->IsPassive() && !Aur->IsPersistent())
3438 for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2)
3440 if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
3442 // Aura can stack on self -> Stack it;
3443 if(aurSpellInfo->StackAmount)
3445 i2->second->modStackAmount(1);
3446 delete Aur;
3447 return false;
3449 // can be only single (this check done at _each_ aura add
3450 RemoveAura(i2,AURA_REMOVE_BY_STACK);
3451 break;
3454 bool stop = false;
3455 switch(aurName)
3457 // DoT/HoT/etc
3458 case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
3459 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
3460 case SPELL_AURA_PERIODIC_LEECH:
3461 case SPELL_AURA_PERIODIC_HEAL:
3462 case SPELL_AURA_OBS_MOD_HEALTH:
3463 case SPELL_AURA_PERIODIC_MANA_LEECH:
3464 case SPELL_AURA_PERIODIC_ENERGIZE:
3465 case SPELL_AURA_OBS_MOD_MANA:
3466 case SPELL_AURA_POWER_BURN_MANA:
3467 break;
3468 default: // not allow
3469 // can be only single (this check done at _each_ aura add
3470 RemoveAura(i2,AURA_REMOVE_BY_STACK);
3471 stop = true;
3472 break;
3475 if(stop)
3476 break;
3481 // passive auras not stacable with other ranks
3482 if (!IsPassiveSpellStackableWithRanks(aurSpellInfo))
3484 if (!RemoveNoStackAurasDueToAura(Aur))
3486 delete Aur;
3487 return false; // couldn't remove conflicting aura with higher rank
3491 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3492 if (Aur->IsSingleTarget() && Aur->GetTarget())
3494 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3495 for(;;)
3497 Unit* caster = Aur->GetCaster();
3498 if(!caster) // caster deleted and not required adding scAura
3499 break;
3501 bool restart = false;
3502 AuraList& scAuras = caster->GetSingleCastAuras();
3503 for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
3505 if( (*itr)->GetTarget() != Aur->GetTarget() &&
3506 IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) )
3508 if ((*itr)->IsInUse())
3510 sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), (*itr)->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
3511 continue;
3513 (*itr)->GetTarget()->RemoveAura((*itr)->GetId(), (*itr)->GetEffIndex());
3514 restart = true;
3515 break;
3519 if(!restart)
3521 // done
3522 scAuras.push_back(Aur);
3523 break;
3528 // add aura, register in lists and arrays
3529 Aur->_AddAura();
3530 m_Auras.insert(AuraMap::value_type(spellEffectPair(Aur->GetId(), Aur->GetEffIndex()), Aur));
3531 if (aurName < TOTAL_AURAS)
3533 m_modAuras[aurName].push_back(Aur);
3536 Aur->ApplyModifier(true,true);
3537 sLog.outDebug("Aura %u now is in use", aurName);
3538 return true;
3541 void Unit::RemoveRankAurasDueToSpell(uint32 spellId)
3543 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
3544 if(!spellInfo)
3545 return;
3546 AuraMap::const_iterator i,next;
3547 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
3549 next = i;
3550 ++next;
3551 uint32 i_spellId = (*i).second->GetId();
3552 if((*i).second && i_spellId && i_spellId != spellId)
3554 if(spellmgr.IsRankSpellDueToSpell(spellInfo,i_spellId))
3556 RemoveAurasDueToSpell(i_spellId);
3558 if( m_Auras.empty() )
3559 break;
3560 else
3561 next = m_Auras.begin();
3567 bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
3569 if (!Aur)
3570 return false;
3572 SpellEntry const* spellProto = Aur->GetSpellProto();
3573 if (!spellProto)
3574 return false;
3576 uint32 spellId = Aur->GetId();
3577 uint32 effIndex = Aur->GetEffIndex();
3579 // passive spell special case (only non stackable with ranks)
3580 if(IsPassiveSpell(spellId))
3582 if(IsPassiveSpellStackableWithRanks(spellProto))
3583 return true;
3586 SpellSpecific spellId_spec = GetSpellSpecific(spellId);
3588 AuraMap::iterator i,next;
3589 for (i = m_Auras.begin(); i != m_Auras.end(); i = next)
3591 next = i;
3592 ++next;
3593 if (!(*i).second) continue;
3595 SpellEntry const* i_spellProto = (*i).second->GetSpellProto();
3597 if (!i_spellProto)
3598 continue;
3600 uint32 i_spellId = i_spellProto->Id;
3602 // early checks that spellId is passive non stackable spell
3603 if(IsPassiveSpell(i_spellId))
3605 // passive non-stackable spells not stackable only for same caster
3606 if(Aur->GetCasterGUID()!=i->second->GetCasterGUID())
3607 continue;
3609 // passive non-stackable spells not stackable only with another rank of same spell
3610 if (!spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
3611 continue;
3614 uint32 i_effIndex = (*i).second->GetEffIndex();
3616 if(i_spellId == spellId) continue;
3618 bool is_triggered_by_spell = false;
3619 // prevent triggered aura of removing aura that triggered it
3620 for(int j = 0; j < 3; ++j)
3621 if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id)
3622 is_triggered_by_spell = true;
3624 if (is_triggered_by_spell)
3625 continue;
3627 SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
3629 bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec);
3630 bool is_sspt = IsSingleFromSpellSpecificRanksPerTarget(spellId_spec,i_spellId_spec);
3632 if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() )
3634 // cannot remove higher rank
3635 if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
3636 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
3637 return false;
3639 // Its a parent aura (create this aura in ApplyModifier)
3640 if ((*i).second->IsInUse())
3642 sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
3643 continue;
3645 RemoveAurasDueToSpell(i_spellId);
3647 if( m_Auras.empty() )
3648 break;
3649 else
3650 next = m_Auras.begin();
3652 else if( is_sspt && Aur->GetCasterGUID() != (*i).second->GetCasterGUID() && spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId) )
3654 // cannot remove higher rank
3655 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
3656 return false;
3658 // Its a parent aura (create this aura in ApplyModifier)
3659 if ((*i).second->IsInUse())
3661 sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
3662 continue;
3664 RemoveAurasDueToSpell(i_spellId);
3666 if( m_Auras.empty() )
3667 break;
3668 else
3669 next = m_Auras.begin();
3671 else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) )
3673 // Its a parent aura (create this aura in ApplyModifier)
3674 if ((*i).second->IsInUse())
3676 sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
3677 continue;
3679 RemoveAurasDueToSpell(i_spellId);
3681 if( m_Auras.empty() )
3682 break;
3683 else
3684 next = m_Auras.begin();
3686 // Potions stack aura by aura (elixirs/flask already checked)
3687 else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION )
3689 if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
3691 if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
3692 return false; // cannot remove higher rank
3694 // Its a parent aura (create this aura in ApplyModifier)
3695 if ((*i).second->IsInUse())
3697 sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
3698 continue;
3700 RemoveAura(i);
3701 next = i;
3705 return true;
3708 void Unit::RemoveAura(uint32 spellId, uint32 effindex, Aura* except)
3710 spellEffectPair spair = spellEffectPair(spellId, effindex);
3711 for(AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
3713 if(iter->second!=except)
3715 RemoveAura(iter);
3716 iter = m_Auras.lower_bound(spair);
3718 else
3719 ++iter;
3723 void Unit::RemoveAurasByCasterSpell(uint32 spellId, uint64 casterGUID)
3725 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3727 Aura *aur = iter->second;
3728 if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
3729 RemoveAura(iter);
3730 else
3731 ++iter;
3735 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler)
3737 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3739 Aura *aur = iter->second;
3740 if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
3742 // Custom dispel case
3743 // Unstable Affliction
3744 if (aur->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (aur->GetSpellProto()->SpellFamilyFlags & UI64LIT(0x010000000000)))
3746 int32 damage = aur->GetModifier()->m_amount*9;
3747 uint64 caster_guid = aur->GetCasterGUID();
3749 // Remove aura
3750 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3752 // backfire damage and silence
3753 dispeler->CastCustomSpell(dispeler, 31117, &damage, NULL, NULL, true, NULL, NULL,caster_guid);
3755 iter = m_Auras.begin(); // iterator can be invalidate at cast if self-dispel
3757 else
3758 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3760 else
3761 ++iter;
3765 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer)
3767 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3769 Aura *aur = iter->second;
3770 if (aur->GetId() == spellId && aur->GetCasterGUID() == casterGUID)
3772 int32 basePoints = aur->GetBasePoints();
3773 // construct the new aura for the attacker - will never return NULL, it's just a wrapper for
3774 // some different constructors
3775 Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, stealer, this);
3777 // set its duration and maximum duration
3778 // max duration 2 minutes (in msecs)
3779 int32 dur = aur->GetAuraDuration();
3780 const int32 max_dur = 2*MINUTE*IN_MILISECONDS;
3781 new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur );
3782 new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur );
3784 // Unregister _before_ adding to stealer
3785 aur->UnregisterSingleCastAura();
3787 // strange but intended behaviour: Stolen single target auras won't be treated as single targeted
3788 new_aur->SetIsSingleTarget(false);
3790 // add the new aura to stealer
3791 stealer->AddAura(new_aur);
3793 // Remove aura as dispel
3794 RemoveAura(iter, AURA_REMOVE_BY_DISPEL);
3796 else
3797 ++iter;
3801 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId)
3803 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3805 if (iter->second->GetId() == spellId)
3806 RemoveAura(iter, AURA_REMOVE_BY_CANCEL);
3807 else
3808 ++iter;
3812 void Unit::RemoveAurasWithDispelType( DispelType type )
3814 // Create dispel mask by dispel type
3815 uint32 dispelMask = GetDispellMask(type);
3816 // Dispel all existing auras vs current dispel type
3817 AuraMap& auras = GetAuras();
3818 for(AuraMap::iterator itr = auras.begin(); itr != auras.end(); )
3820 SpellEntry const* spell = itr->second->GetSpellProto();
3821 if( (1<<spell->Dispel) & dispelMask )
3823 // Dispel aura
3824 RemoveAurasDueToSpell(spell->Id);
3825 itr = auras.begin();
3827 else
3828 ++itr;
3832 void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
3834 AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
3835 if(iter != m_Auras.end())
3837 if (iter->second->modStackAmount(-1))
3838 RemoveAura(iter);
3842 void Unit::RemoveSingleSpellAurasFromStack(uint32 spellId)
3844 for (int i=0; i<3; ++i)
3845 RemoveSingleAuraFromStack(spellId, i);
3848 void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
3850 for (int i = 0; i < 3; ++i)
3851 RemoveAura(spellId,i,except);
3854 void Unit::RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId)
3856 for (int k=0; k < 3; ++k)
3858 spellEffectPair spair = spellEffectPair(spellId, k);
3859 for (AuraMap::iterator iter = m_Auras.lower_bound(spair); iter != m_Auras.upper_bound(spair);)
3861 if (iter->second->GetCastItemGUID() == castItem->GetGUID())
3863 RemoveAura(iter);
3864 iter = m_Auras.upper_bound(spair); // overwrite by more appropriate
3866 else
3867 ++iter;
3872 void Unit::RemoveAurasWithInterruptFlags(uint32 flags)
3874 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3876 if (iter->second->GetSpellProto()->AuraInterruptFlags & flags)
3877 RemoveAura(iter);
3878 else
3879 ++iter;
3883 void Unit::RemoveNotOwnSingleTargetAuras()
3885 // single target auras from other casters
3886 for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
3888 if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
3889 RemoveAura(iter);
3890 else
3891 ++iter;
3894 // single target auras at other targets
3895 AuraList& scAuras = GetSingleCastAuras();
3896 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end(); )
3898 Aura* aura = *iter;
3899 if (aura->GetTarget()!=this)
3901 scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveAura
3902 aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetEffIndex());
3903 iter = scAuras.begin();
3905 else
3906 ++iter;
3911 void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
3913 Aura* Aur = i->second;
3914 SpellEntry const* AurSpellInfo = Aur->GetSpellProto();
3916 Aur->UnregisterSingleCastAura();
3918 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3919 if (Aur->GetModifier()->m_auraname < TOTAL_AURAS)
3921 m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur);
3924 // Set remove mode
3925 Aur->SetRemoveMode(mode);
3926 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
3927 // remove aura from list before to prevent deleting it before
3928 m_Auras.erase(i);
3929 ++m_removedAuras; // internal count used by unit update
3931 // Statue unsummoned at aura remove
3932 Totem* statue = NULL;
3933 bool caster_channeled = false;
3934 if(IsChanneledSpell(AurSpellInfo))
3936 Unit* caster = Aur->GetCaster();
3938 if(caster)
3940 if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE)
3941 statue = ((Totem*)caster);
3942 else
3943 caster_channeled = caster==this;
3947 sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode);
3948 Aur->ApplyModifier(false,true);
3949 Aur->_RemoveAura();
3950 delete Aur;
3952 if(caster_channeled)
3953 RemoveAurasAtChanneledTarget (AurSpellInfo);
3955 if(statue)
3956 statue->UnSummon();
3958 // only way correctly remove all auras from list
3959 if( m_Auras.empty() )
3960 i = m_Auras.end();
3961 else
3962 i = m_Auras.begin();
3965 void Unit::RemoveAllAuras()
3967 while (!m_Auras.empty())
3969 AuraMap::iterator iter = m_Auras.begin();
3970 RemoveAura(iter);
3974 void Unit::RemoveArenaAuras(bool onleave)
3976 // in join, remove positive buffs, on end, remove negative
3977 // used to remove positive visible auras in arenas
3978 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
3980 if ( !(iter->second->GetSpellProto()->AttributesEx4 & (1<<21)) // don't remove stances, shadowform, pally/hunter auras
3981 && !iter->second->IsPassive() // don't remove passive auras
3982 && (!(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || !(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNK8)) // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable)
3983 && (iter->second->IsPositive() ^ onleave)) // remove positive buffs on enter, negative buffs on leave
3984 RemoveAura(iter);
3985 else
3986 ++iter;
3990 void Unit::RemoveAllAurasOnDeath()
3992 // used just after dieing to remove all visible auras
3993 // and disable the mods for the passive ones
3994 for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
3996 if (!iter->second->IsPassive() && !iter->second->IsDeathPersistent())
3997 RemoveAura(iter, AURA_REMOVE_BY_DEATH);
3998 else
3999 ++iter;
4003 void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime)
4005 AuraMap::const_iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4006 if (iter != m_Auras.end())
4008 if (iter->second->GetAuraDuration() < delaytime)
4009 iter->second->SetAuraDuration(0);
4010 else
4011 iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime);
4012 iter->second->SendAuraUpdate(false);
4013 sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration());
4017 void Unit::_RemoveAllAuraMods()
4019 for (AuraMap::const_iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4021 (*i).second->ApplyModifier(false);
4025 void Unit::_ApplyAllAuraMods()
4027 for (AuraMap::const_iterator i = m_Auras.begin(); i != m_Auras.end(); ++i)
4029 (*i).second->ApplyModifier(true);
4033 Aura* Unit::GetAura(uint32 spellId, uint32 effindex)
4035 AuraMap::const_iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
4036 if (iter != m_Auras.end())
4037 return iter->second;
4038 return NULL;
4041 Aura* Unit::GetAura(AuraType type, uint32 family, uint64 familyFlag, uint32 familyFlag2, uint64 casterGUID)
4043 AuraList const& auras = GetAurasByType(type);
4044 for(AuraList::const_iterator i = auras.begin();i != auras.end(); ++i)
4046 SpellEntry const *spell = (*i)->GetSpellProto();
4047 if (spell->SpellFamilyName == family && (spell->SpellFamilyFlags & familyFlag || spell->SpellFamilyFlags2 & familyFlag2))
4049 if (casterGUID && (*i)->GetCasterGUID()!=casterGUID)
4050 continue;
4051 return (*i);
4054 return NULL;
4057 bool Unit::HasAura(uint32 spellId) const
4059 for (int i = 0; i < 3 ; ++i)
4061 AuraMap::const_iterator iter = m_Auras.find(spellEffectPair(spellId, i));
4062 if (iter != m_Auras.end())
4063 return true;
4065 return false;
4068 void Unit::AddDynObject(DynamicObject* dynObj)
4070 m_dynObjGUIDs.push_back(dynObj->GetGUID());
4073 void Unit::RemoveDynObject(uint32 spellid)
4075 if(m_dynObjGUIDs.empty())
4076 return;
4077 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4079 DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4080 if(!dynObj)
4082 i = m_dynObjGUIDs.erase(i);
4084 else if(spellid == 0 || dynObj->GetSpellId() == spellid)
4086 dynObj->Delete();
4087 i = m_dynObjGUIDs.erase(i);
4089 else
4090 ++i;
4094 void Unit::RemoveAllDynObjects()
4096 while(!m_dynObjGUIDs.empty())
4098 DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin());
4099 if(dynObj)
4100 dynObj->Delete();
4101 m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
4105 DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
4107 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4109 DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4110 if(!dynObj)
4112 i = m_dynObjGUIDs.erase(i);
4113 continue;
4116 if (dynObj->GetSpellId() == spellId && dynObj->GetEffIndex() == effIndex)
4117 return dynObj;
4118 ++i;
4120 return NULL;
4123 DynamicObject * Unit::GetDynObject(uint32 spellId)
4125 for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
4127 DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
4128 if(!dynObj)
4130 i = m_dynObjGUIDs.erase(i);
4131 continue;
4134 if (dynObj->GetSpellId() == spellId)
4135 return dynObj;
4136 ++i;
4138 return NULL;
4141 GameObject* Unit::GetGameObject(uint32 spellId) const
4143 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
4144 if ((*i)->GetSpellId() == spellId)
4145 return *i;
4147 return NULL;
4150 void Unit::AddGameObject(GameObject* gameObj)
4152 assert(gameObj && gameObj->GetOwnerGUID()==0);
4153 m_gameObj.push_back(gameObj);
4154 gameObj->SetOwnerGUID(GetGUID());
4156 if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() )
4158 SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
4159 // Need disable spell use for owner
4160 if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
4161 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
4162 ((Player*)this)->AddSpellAndCategoryCooldowns(createBySpell,0,NULL,true);
4166 void Unit::RemoveGameObject(GameObject* gameObj, bool del)
4168 assert(gameObj && gameObj->GetOwnerGUID()==GetGUID());
4170 gameObj->SetOwnerGUID(0);
4172 // GO created by some spell
4173 if (uint32 spellid = gameObj->GetSpellId())
4175 RemoveAurasDueToSpell(spellid);
4177 if (GetTypeId()==TYPEID_PLAYER)
4179 SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid );
4180 // Need activate spell use for owner
4181 if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
4182 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
4183 ((Player*)this)->SendCooldownEvent(createBySpell);
4187 m_gameObj.remove(gameObj);
4189 if(del)
4191 gameObj->SetRespawnTime(0);
4192 gameObj->Delete();
4196 void Unit::RemoveGameObject(uint32 spellid, bool del)
4198 if(m_gameObj.empty())
4199 return;
4200 GameObjectList::iterator i, next;
4201 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
4203 next = i;
4204 if(spellid == 0 || (*i)->GetSpellId() == spellid)
4206 (*i)->SetOwnerGUID(0);
4207 if(del)
4209 (*i)->SetRespawnTime(0);
4210 (*i)->Delete();
4213 next = m_gameObj.erase(i);
4215 else
4216 ++next;
4220 void Unit::RemoveAllGameObjects()
4222 // remove references to unit
4223 for(GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
4225 (*i)->SetOwnerGUID(0);
4226 (*i)->SetRespawnTime(0);
4227 (*i)->Delete();
4228 i = m_gameObj.erase(i);
4232 void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
4234 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size
4235 data.append(log->target->GetPackGUID());
4236 data.append(log->attacker->GetPackGUID());
4237 data << uint32(log->SpellID);
4238 data << uint32(log->damage); // damage amount
4239 data << uint32(log->overkill); // overkill
4240 data << uint8 (log->schoolMask); // damage school
4241 data << uint32(log->absorb); // AbsorbedDamage
4242 data << uint32(log->resist); // resist
4243 data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
4244 data << uint8 (log->unused); // unused
4245 data << uint32(log->blocked); // blocked
4246 data << uint32(log->HitInfo);
4247 data << uint8 (0); // flag to use extend data
4248 SendMessageToSet( &data, true );
4251 void Unit::SendSpellNonMeleeDamageLog(Unit *target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
4253 SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask);
4254 log.damage = Damage - AbsorbedDamage - Resist - Blocked;
4255 log.absorb = AbsorbedDamage;
4256 log.resist = Resist;
4257 log.physicalLog = PhysicalDamage;
4258 log.blocked = Blocked;
4259 log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6;
4260 if(CriticalHit)
4261 log.HitInfo |= SPELL_HIT_TYPE_CRIT;
4262 SendSpellNonMeleeDamageLog(&log);
4265 void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
4267 Aura *aura = pInfo->aura;
4268 Modifier *mod = aura->GetModifier();
4270 WorldPacket data(SMSG_PERIODICAURALOG, 30);
4271 data.append(aura->GetTarget()->GetPackGUID());
4272 data.appendPackGUID(aura->GetCasterGUID());
4273 data << uint32(aura->GetId()); // spellId
4274 data << uint32(1); // count
4275 data << uint32(mod->m_auraname); // auraId
4276 switch(mod->m_auraname)
4278 case SPELL_AURA_PERIODIC_DAMAGE:
4279 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
4280 data << uint32(pInfo->damage); // damage
4281 data << uint32(pInfo->overDamage); // overkill?
4282 data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
4283 data << uint32(pInfo->absorb); // absorb
4284 data << uint32(pInfo->resist); // resist
4285 data << uint8(0); // new 3.1.2
4286 break;
4287 case SPELL_AURA_PERIODIC_HEAL:
4288 case SPELL_AURA_OBS_MOD_HEALTH:
4289 data << uint32(pInfo->damage); // damage
4290 data << uint32(pInfo->overDamage); // overheal?
4291 data << uint8(0); // new 3.1.2
4292 break;
4293 case SPELL_AURA_OBS_MOD_MANA:
4294 case SPELL_AURA_PERIODIC_ENERGIZE:
4295 data << uint32(mod->m_miscvalue); // power type
4296 data << uint32(pInfo->damage); // damage
4297 break;
4298 case SPELL_AURA_PERIODIC_MANA_LEECH:
4299 data << uint32(mod->m_miscvalue); // power type
4300 data << uint32(pInfo->damage); // amount
4301 data << float(pInfo->multiplier); // gain multiplier
4302 break;
4303 default:
4304 sLog.outError("Unit::SendPeriodicAuraLog: unknown aura %u", uint32(mod->m_auraname));
4305 return;
4308 aura->GetTarget()->SendMessageToSet(&data, true);
4311 void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell)
4313 // Not much to do if no flags are set.
4314 if (procAttacker)
4315 ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, amount);
4316 // Now go on with a victim's events'n'auras
4317 // Not much to do if no flags are set or there is no victim
4318 if(pVictim && pVictim->isAlive() && procVictim)
4319 pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra, attType, procSpell, amount);
4322 void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
4324 WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
4325 data << uint32(spellID);
4326 data << uint64(GetGUID());
4327 data << uint8(0); // can be 0 or 1
4328 data << uint32(1); // target count
4329 // for(i = 0; i < target count; ++i)
4330 data << uint64(target->GetGUID()); // target GUID
4331 data << uint8(missInfo);
4332 // end loop
4333 SendMessageToSet(&data, true);
4336 void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
4338 sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4340 uint32 count = 1;
4341 WorldPacket data(SMSG_ATTACKERSTATEUPDATE, 16 + 45); // we guess size
4342 data << uint32(damageInfo->HitInfo);
4343 data.append(damageInfo->attacker->GetPackGUID());
4344 data.append(damageInfo->target->GetPackGUID());
4345 data << uint32(damageInfo->damage); // Full damage
4346 data << uint32(0); // overkill value
4347 data << uint8(count); // Sub damage count
4349 for(int i = 0; i < count; ++i)
4351 data << uint32(damageInfo->damageSchoolMask); // School of sub damage
4352 data << float(damageInfo->damage); // sub damage
4353 data << uint32(damageInfo->damage); // Sub Damage
4356 if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2))
4358 for(int i = 0; i < count; ++i)
4359 data << uint32(damageInfo->absorb); // Absorb
4362 if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2))
4364 for(int i = 0; i < count; ++i)
4365 data << uint32(damageInfo->resist); // Resist
4368 data << uint8(damageInfo->TargetState);
4369 data << uint32(0);
4370 data << uint32(0);
4372 if(damageInfo->HitInfo & HITINFO_BLOCK)
4373 data << uint32(damageInfo->blocked_amount);
4375 if(damageInfo->HitInfo & HITINFO_UNK3)
4376 data << uint32(0);
4378 if(damageInfo->HitInfo & HITINFO_UNK1)
4380 data << uint32(0);
4381 data << float(0);
4382 data << float(0);
4383 data << float(0);
4384 data << float(0);
4385 data << float(0);
4386 data << float(0);
4387 data << float(0);
4388 data << float(0);
4389 for(uint8 i = 0; i < 5; ++i)
4391 data << float(0);
4392 data << float(0);
4394 data << uint32(0);
4397 SendMessageToSet( &data, true );
4400 void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
4402 CalcDamageInfo dmgInfo;
4403 dmgInfo.HitInfo = HitInfo;
4404 dmgInfo.attacker = this;
4405 dmgInfo.target = target;
4406 dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount;
4407 dmgInfo.damageSchoolMask = damageSchoolMask;
4408 dmgInfo.absorb = AbsorbDamage;
4409 dmgInfo.resist = Resist;
4410 dmgInfo.TargetState = TargetState;
4411 dmgInfo.blocked_amount = BlockedAmount;
4412 SendAttackStateUpdate(&dmgInfo);
4415 bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
4417 SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
4419 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4420 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
4422 uint32 triggered_spell_id = 0;
4423 Unit* target = pVictim;
4424 int32 basepoints0 = 0;
4426 switch(hasteSpell->SpellFamilyName)
4428 case SPELLFAMILY_ROGUE:
4430 switch(hasteSpell->Id)
4432 // Blade Flurry
4433 case 13877:
4434 case 33735:
4436 target = SelectNearbyTarget();
4437 if(!target)
4438 return false;
4439 basepoints0 = damage;
4440 triggered_spell_id = 22482;
4441 break;
4444 break;
4448 // processed charge only counting case
4449 if(!triggered_spell_id)
4450 return true;
4452 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
4454 if(!triggerEntry)
4456 sLog.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell->Id,triggered_spell_id);
4457 return false;
4460 // default case
4461 if(!target || target!=this && !target->isAlive())
4462 return false;
4464 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
4465 return false;
4467 if(basepoints0)
4468 CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
4469 else
4470 CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
4472 if( cooldown && GetTypeId()==TYPEID_PLAYER )
4473 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
4475 return true;
4478 bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
4480 SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
4481 uint32 effIndex = triggeredByAura->GetEffIndex();
4482 int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
4484 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4485 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
4487 uint32 triggered_spell_id = 0;
4488 Unit* target = pVictim;
4489 int32 basepoints0 = 0;
4491 switch(dummySpell->SpellFamilyName)
4493 case SPELLFAMILY_GENERIC:
4495 switch (dummySpell->Id)
4497 // Eye for an Eye
4498 case 9799:
4499 case 25988:
4501 // return damage % to attacker but < 50% own total health
4502 basepoints0 = triggerAmount*int32(damage)/100;
4503 if(basepoints0 > GetMaxHealth()/2)
4504 basepoints0 = GetMaxHealth()/2;
4506 triggered_spell_id = 25997;
4507 break;
4509 // Sweeping Strikes
4510 case 12328:
4511 case 18765:
4512 case 35429:
4514 // prevent chain of triggered spell from same triggered spell
4515 if(procSpell && procSpell->Id==26654)
4516 return false;
4518 target = SelectNearbyTarget();
4519 if(!target)
4520 return false;
4522 triggered_spell_id = 26654;
4523 break;
4525 // Unstable Power
4526 case 24658:
4528 if (!procSpell || procSpell->Id == 24659)
4529 return false;
4530 // Need remove one 24659 aura
4531 RemoveSingleSpellAurasFromStack(24659);
4532 return true;
4534 // Restless Strength
4535 case 24661:
4537 // Need remove one 24662 aura
4538 RemoveSingleSpellAurasFromStack(24662);
4539 return true;
4541 // Adaptive Warding (Frostfire Regalia set)
4542 case 28764:
4544 if(!procSpell)
4545 return false;
4547 // find Mage Armor
4548 bool found = false;
4549 AuraList const& mRegenInterupt = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
4550 for(AuraList::const_iterator iter = mRegenInterupt.begin(); iter != mRegenInterupt.end(); ++iter)
4552 if(SpellEntry const* iterSpellProto = (*iter)->GetSpellProto())
4554 if(iterSpellProto->SpellFamilyName==SPELLFAMILY_MAGE && (iterSpellProto->SpellFamilyFlags & UI64LIT(0x10000000)))
4556 found=true;
4557 break;
4561 if(!found)
4562 return false;
4564 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
4566 case SPELL_SCHOOL_NORMAL:
4567 case SPELL_SCHOOL_HOLY:
4568 return false; // ignored
4569 case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
4570 case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
4571 case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
4572 case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
4573 case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
4574 default:
4575 return false;
4578 target = this;
4579 break;
4581 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4582 case 27539:
4584 if(!procSpell)
4585 return false;
4587 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
4589 case SPELL_SCHOOL_NORMAL:
4590 return false; // ignore
4591 case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
4592 case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
4593 case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
4594 case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
4595 case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
4596 case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
4597 default:
4598 return false;
4601 target = this;
4602 break;
4604 // Mana Leech (Passive) (Priest Pet Aura)
4605 case 28305:
4607 // Cast on owner
4608 target = GetOwner();
4609 if(!target)
4610 return false;
4612 triggered_spell_id = 34650;
4613 break;
4615 // Mark of Malice
4616 case 33493:
4618 // Cast finish spell at last charge
4619 if (triggeredByAura->GetAuraCharges() > 1)
4620 return false;
4622 target = this;
4623 triggered_spell_id = 33494;
4624 break;
4626 // Twisted Reflection (boss spell)
4627 case 21063:
4628 triggered_spell_id = 21064;
4629 break;
4630 // Vampiric Aura (boss spell)
4631 case 38196:
4633 basepoints0 = 3 * damage; // 300%
4634 if (basepoints0 < 0)
4635 return false;
4637 triggered_spell_id = 31285;
4638 target = this;
4639 break;
4641 // Aura of Madness (Darkmoon Card: Madness trinket)
4642 //=====================================================
4643 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4644 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4645 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4646 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4647 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4648 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4649 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4650 // 41011 Martyr Complex: +35 stamina (All classes)
4651 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4652 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4653 case 39446:
4655 if(GetTypeId() != TYPEID_PLAYER)
4656 return false;
4658 // Select class defined buff
4659 switch (getClass())
4661 case CLASS_PALADIN: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4662 case CLASS_DRUID: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4664 uint32 RandomSpell[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4665 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4666 break;
4668 case CLASS_ROGUE: // 39511,40997,40998,41002,41005,41011
4669 case CLASS_WARRIOR: // 39511,40997,40998,41002,41005,41011
4671 uint32 RandomSpell[]={39511,40997,40998,41002,41005,41011};
4672 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4673 break;
4675 case CLASS_PRIEST: // 40999,41002,41005,41009,41011,41406,41409
4676 case CLASS_SHAMAN: // 40999,41002,41005,41009,41011,41406,41409
4677 case CLASS_MAGE: // 40999,41002,41005,41009,41011,41406,41409
4678 case CLASS_WARLOCK: // 40999,41002,41005,41009,41011,41406,41409
4680 uint32 RandomSpell[]={40999,41002,41005,41009,41011,41406,41409};
4681 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4682 break;
4684 case CLASS_HUNTER: // 40997,40999,41002,41005,41009,41011,41406,41409
4686 uint32 RandomSpell[]={40997,40999,41002,41005,41009,41011,41406,41409};
4687 triggered_spell_id = RandomSpell[ irand(0, sizeof(RandomSpell)/sizeof(uint32) - 1) ];
4688 break;
4690 default:
4691 return false;
4694 target = this;
4695 if (roll_chance_i(10))
4696 ((Player*)this)->Say("This is Madness!", LANG_UNIVERSAL);
4697 break;
4700 // TODO: need find item for aura and triggered spells
4701 // Sunwell Exalted Caster Neck (??? neck)
4702 // cast ??? Light's Wrath if Exalted by Aldor
4703 // cast ??? Arcane Bolt if Exalted by Scryers*/
4704 case 46569:
4705 return false; // disable for while
4708 if(GetTypeId() != TYPEID_PLAYER)
4709 return false;
4711 // Get Aldor reputation rank
4712 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4714 target = this;
4715 triggered_spell_id = ???
4716 break;
4718 // Get Scryers reputation rank
4719 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4721 triggered_spell_id = ???
4722 break;
4724 return false;
4726 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4727 // cast 45479 Light's Wrath if Exalted by Aldor
4728 // cast 45429 Arcane Bolt if Exalted by Scryers
4729 case 45481:
4731 if(GetTypeId() != TYPEID_PLAYER)
4732 return false;
4734 // Get Aldor reputation rank
4735 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4737 target = this;
4738 triggered_spell_id = 45479;
4739 break;
4741 // Get Scryers reputation rank
4742 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4744 triggered_spell_id = 45429;
4745 break;
4747 return false;
4749 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4750 // cast 45480 Light's Strength if Exalted by Aldor
4751 // cast 45428 Arcane Strike if Exalted by Scryers
4752 case 45482:
4754 if(GetTypeId() != TYPEID_PLAYER)
4755 return false;
4757 // Get Aldor reputation rank
4758 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4760 target = this;
4761 triggered_spell_id = 45480;
4762 break;
4764 // Get Scryers reputation rank
4765 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4767 triggered_spell_id = 45428;
4768 break;
4770 return false;
4772 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4773 // cast 45431 Arcane Insight if Exalted by Aldor
4774 // cast 45432 Light's Ward if Exalted by Scryers
4775 case 45483:
4777 if(GetTypeId() != TYPEID_PLAYER)
4778 return false;
4780 // Get Aldor reputation rank
4781 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4783 target = this;
4784 triggered_spell_id = 45432;
4785 break;
4787 // Get Scryers reputation rank
4788 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4790 target = this;
4791 triggered_spell_id = 45431;
4792 break;
4794 return false;
4796 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4797 // cast 45478 Light's Salvation if Exalted by Aldor
4798 // cast 45430 Arcane Surge if Exalted by Scryers
4799 case 45484:
4801 if(GetTypeId() != TYPEID_PLAYER)
4802 return false;
4804 // Get Aldor reputation rank
4805 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4807 target = this;
4808 triggered_spell_id = 45478;
4809 break;
4811 // Get Scryers reputation rank
4812 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4814 triggered_spell_id = 45430;
4815 break;
4817 return false;
4819 // Living Seed
4820 case 48504:
4822 triggered_spell_id = 48503;
4823 basepoints0 = triggerAmount;
4824 target = this;
4825 break;
4827 // Vampiric Touch (generic, used by some boss)
4828 case 52723:
4829 case 60501:
4831 triggered_spell_id = 52724;
4832 basepoints0 = damage / 2;
4833 target = this;
4834 break;
4836 // Divine purpose
4837 case 31871:
4838 case 31872:
4840 // Roll chane
4841 if (!roll_chance_i(triggerAmount))
4842 return false;
4844 // Remove any stun effect on target
4845 AuraMap& Auras = pVictim->GetAuras();
4846 for(AuraMap::const_iterator iter = Auras.begin(); iter != Auras.end();)
4848 SpellEntry const *spell = iter->second->GetSpellProto();
4849 if( spell->Mechanic == MECHANIC_STUN ||
4850 spell->EffectMechanic[iter->second->GetEffIndex()] == MECHANIC_STUN)
4852 pVictim->RemoveAurasDueToSpell(spell->Id);
4853 iter = Auras.begin();
4855 else
4856 ++iter;
4858 return true;
4861 break;
4863 case SPELLFAMILY_MAGE:
4865 // Magic Absorption
4866 if (dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura
4868 if (getPowerType() != POWER_MANA)
4869 return false;
4871 // mana reward
4872 basepoints0 = (triggerAmount * GetMaxPower(POWER_MANA) / 100);
4873 target = this;
4874 triggered_spell_id = 29442;
4875 break;
4877 // Master of Elements
4878 if (dummySpell->SpellIconID == 1920)
4880 if(!procSpell)
4881 return false;
4883 // mana cost save
4884 int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
4885 basepoints0 = cost * triggerAmount/100;
4886 if( basepoints0 <=0 )
4887 return false;
4889 target = this;
4890 triggered_spell_id = 29077;
4891 break;
4894 // Arcane Potency
4895 if (dummySpell->SpellIconID == 2120)
4897 if(!procSpell)
4898 return false;
4900 target = this;
4901 switch (dummySpell->Id)
4903 case 31571: triggered_spell_id = 57529; break;
4904 case 31572: triggered_spell_id = 57531; break;
4905 default:
4906 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u",dummySpell->Id);
4907 return false;
4909 break;
4912 // Hot Streak
4913 if (dummySpell->SpellIconID == 2999)
4915 if (effIndex!=0)
4916 return true;
4917 Aura *counter = GetAura(triggeredByAura->GetId(), 1);
4918 if (!counter)
4919 return true;
4921 // Count spell criticals in a row in second aura
4922 Modifier *mod = counter->GetModifier();
4923 if (procEx & PROC_EX_CRITICAL_HIT)
4925 mod->m_amount *=2;
4926 if (mod->m_amount < 100) // not enough
4927 return true;
4928 // Crititcal counted -> roll chance
4929 if (roll_chance_i(triggerAmount))
4930 CastSpell(this, 48108, true, castItem, triggeredByAura);
4932 mod->m_amount = 25;
4933 return true;
4935 // Burnout
4936 if (dummySpell->SpellIconID == 2998)
4938 if(!procSpell)
4939 return false;
4941 int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
4942 basepoints0 = cost * triggerAmount/100;
4943 if( basepoints0 <=0 )
4944 return false;
4945 triggered_spell_id = 44450;
4946 target = this;
4947 break;
4949 // Incanter's Regalia set (add trigger chance to Mana Shield)
4950 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000000000008000))
4952 if(GetTypeId() != TYPEID_PLAYER)
4953 return false;
4955 target = this;
4956 triggered_spell_id = 37436;
4957 break;
4959 switch(dummySpell->Id)
4961 // Ignite
4962 case 11119:
4963 case 11120:
4964 case 12846:
4965 case 12847:
4966 case 12848:
4968 switch (dummySpell->Id)
4970 case 11119: basepoints0 = int32(0.04f*damage); break;
4971 case 11120: basepoints0 = int32(0.08f*damage); break;
4972 case 12846: basepoints0 = int32(0.12f*damage); break;
4973 case 12847: basepoints0 = int32(0.16f*damage); break;
4974 case 12848: basepoints0 = int32(0.20f*damage); break;
4975 default:
4976 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell->Id);
4977 return false;
4980 triggered_spell_id = 12654;
4981 break;
4983 // Combustion
4984 case 11129:
4986 //last charge and crit
4987 if (triggeredByAura->GetAuraCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT) )
4989 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
4990 return true; // charge counting (will removed)
4993 CastSpell(this, 28682, true, castItem, triggeredByAura);
4994 return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns
4997 break;
4999 case SPELLFAMILY_WARRIOR:
5001 // Retaliation
5002 if (dummySpell->SpellFamilyFlags == UI64LIT(0x0000000800000000))
5004 // check attack comes not from behind
5005 if (!HasInArc(M_PI, pVictim))
5006 return false;
5008 triggered_spell_id = 22858;
5009 break;
5011 // Second Wind
5012 if (dummySpell->SpellIconID == 1697)
5014 // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example)
5015 if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
5016 return false;
5017 // Need stun or root mechanic
5018 if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN))))
5019 return false;
5021 switch (dummySpell->Id)
5023 case 29838: triggered_spell_id=29842; break;
5024 case 29834: triggered_spell_id=29841; break;
5025 case 42770: triggered_spell_id=42771; break;
5026 default:
5027 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id);
5028 return false;
5031 target = this;
5032 break;
5034 // Damage Shield
5035 if (dummySpell->SpellIconID == 3214)
5037 triggered_spell_id = 59653;
5038 basepoints0 = GetShieldBlockValue() * triggerAmount / 100;
5039 break;
5041 break;
5043 case SPELLFAMILY_WARLOCK:
5045 // Seed of Corruption
5046 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000001000000000))
5048 Modifier* mod = triggeredByAura->GetModifier();
5049 // if damage is more than need or target die from damage deal finish spell
5050 if( mod->m_amount <= damage || GetHealth() <= damage )
5052 // remember guid before aura delete
5053 uint64 casterGuid = triggeredByAura->GetCasterGUID();
5055 // Remove aura (before cast for prevent infinite loop handlers)
5056 RemoveAurasDueToSpell(triggeredByAura->GetId());
5058 // Cast finish spell (triggeredByAura already not exist!)
5059 CastSpell(this, 27285, true, castItem, NULL, casterGuid);
5060 return true; // no hidden cooldown
5063 // Damage counting
5064 mod->m_amount-=damage;
5065 return true;
5067 // Seed of Corruption (Mobs cast) - no die req
5068 if (dummySpell->SpellFamilyFlags == UI64LIT(0x0) && dummySpell->SpellIconID == 1932)
5070 Modifier* mod = triggeredByAura->GetModifier();
5071 // if damage is more than need deal finish spell
5072 if( mod->m_amount <= damage )
5074 // remember guid before aura delete
5075 uint64 casterGuid = triggeredByAura->GetCasterGUID();
5077 // Remove aura (before cast for prevent infinite loop handlers)
5078 RemoveAurasDueToSpell(triggeredByAura->GetId());
5080 // Cast finish spell (triggeredByAura already not exist!)
5081 CastSpell(this, 32865, true, castItem, NULL, casterGuid);
5082 return true; // no hidden cooldown
5084 // Damage counting
5085 mod->m_amount-=damage;
5086 return true;
5088 // Fel Synergy
5089 if (dummySpell->SpellIconID == 3222)
5091 target = GetPet();
5092 if (!target)
5093 return false;
5094 basepoints0 = damage * triggerAmount / 100;
5095 triggered_spell_id = 54181;
5096 break;
5098 switch(dummySpell->Id)
5100 // Nightfall
5101 case 18094:
5102 case 18095:
5104 target = this;
5105 triggered_spell_id = 17941;
5106 break;
5108 //Soul Leech
5109 case 30293:
5110 case 30295:
5111 case 30296:
5113 // health
5114 basepoints0 = int32(damage*triggerAmount/100);
5115 target = this;
5116 triggered_spell_id = 30294;
5117 break;
5119 // Shadowflame (Voidheart Raiment set bonus)
5120 case 37377:
5122 triggered_spell_id = 37379;
5123 break;
5125 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5126 case 37381:
5128 target = GetPet();
5129 if(!target)
5130 return false;
5132 // heal amount
5133 basepoints0 = damage * triggerAmount/100;
5134 triggered_spell_id = 37382;
5135 break;
5137 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5138 case 39437:
5140 triggered_spell_id = 37378;
5141 break;
5143 // Siphon Life
5144 case 63108:
5146 basepoints0 = int32(damage * triggerAmount / 100);
5147 triggered_spell_id = 63106;
5148 break;
5151 break;
5153 case SPELLFAMILY_PRIEST:
5155 // Vampiric Touch
5156 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000040000000000))
5158 if(!pVictim || !pVictim->isAlive())
5159 return false;
5161 // pVictim is caster of aura
5162 if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID())
5163 return false;
5165 // Energize 0.25% of max. mana
5166 pVictim->CastSpell(pVictim,57669,true,castItem,triggeredByAura);
5167 return true; // no hidden cooldown
5169 // Divine Aegis
5170 if (dummySpell->SpellIconID == 2820)
5172 basepoints0 = damage * triggerAmount/100;
5173 triggered_spell_id = 47753;
5174 break;
5176 switch(dummySpell->Id)
5178 // Vampiric Embrace
5179 case 15286:
5181 if(!pVictim || !pVictim->isAlive())
5182 return false;
5184 // pVictim is caster of aura
5185 if(triggeredByAura->GetCasterGUID() != pVictim->GetGUID())
5186 return false;
5188 // heal amount
5189 int32 team = triggerAmount*damage/500;
5190 int32 self = triggerAmount*damage/100 - team;
5191 pVictim->CastCustomSpell(pVictim,15290,&team,&self,NULL,true,castItem,triggeredByAura);
5192 return true; // no hidden cooldown
5194 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5195 case 40438:
5197 // Shadow Word: Pain
5198 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000008000))
5199 triggered_spell_id = 40441;
5200 // Renew
5201 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000010))
5202 triggered_spell_id = 40440;
5203 else
5204 return false;
5206 target = this;
5207 break;
5209 // Oracle Healing Bonus ("Garments of the Oracle" set)
5210 case 26169:
5212 // heal amount
5213 basepoints0 = int32(damage * 10/100);
5214 target = this;
5215 triggered_spell_id = 26170;
5216 break;
5218 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5219 case 39372:
5221 if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 )
5222 return false;
5224 // heal amount
5225 basepoints0 = damage * triggerAmount/100;
5226 target = this;
5227 triggered_spell_id = 39373;
5228 break;
5230 // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
5231 case 28809:
5233 triggered_spell_id = 28810;
5234 break;
5236 // Glyph of Dispel Magic
5237 case 55677:
5239 if(!target->IsFriendlyTo(this))
5240 return false;
5242 basepoints0 = int32(target->GetMaxHealth() * triggerAmount / 100);
5243 triggered_spell_id = 56131;
5244 break;
5247 break;
5249 case SPELLFAMILY_DRUID:
5251 switch(dummySpell->Id)
5253 // Healing Touch (Dreamwalker Raiment set)
5254 case 28719:
5256 // mana back
5257 basepoints0 = int32(procSpell->manaCost * 30 / 100);
5258 target = this;
5259 triggered_spell_id = 28742;
5260 break;
5262 // Healing Touch Refund (Idol of Longevity trinket)
5263 case 28847:
5265 target = this;
5266 triggered_spell_id = 28848;
5267 break;
5269 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5270 case 37288:
5271 case 37295:
5273 target = this;
5274 triggered_spell_id = 37238;
5275 break;
5277 // Druid Tier 6 Trinket
5278 case 40442:
5280 float chance;
5282 // Starfire
5283 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000004))
5285 triggered_spell_id = 40445;
5286 chance = 25.0f;
5288 // Rejuvenation
5289 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000010))
5291 triggered_spell_id = 40446;
5292 chance = 25.0f;
5294 // Mangle (cat/bear)
5295 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000044000000000))
5297 triggered_spell_id = 40452;
5298 chance = 40.0f;
5300 else
5301 return false;
5303 if (!roll_chance_f(chance))
5304 return false;
5306 target = this;
5307 break;
5309 // Maim Interrupt
5310 case 44835:
5312 // Deadly Interrupt Effect
5313 triggered_spell_id = 32747;
5314 break;
5317 // Eclipse
5318 if (dummySpell->SpellIconID == 2856)
5320 if (!procSpell)
5321 return false;
5322 // Only 0 aura can proc
5323 if (effIndex!=0)
5324 return true;
5325 // Wrath crit
5326 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000001))
5328 if (!roll_chance_i(60))
5329 return false;
5330 triggered_spell_id = 48518;
5331 target = this;
5332 break;
5334 // Starfire crit
5335 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000004))
5337 triggered_spell_id = 48517;
5338 target = this;
5339 break;
5341 return false;
5343 // Living Seed
5344 else if (dummySpell->SpellIconID == 2860)
5346 triggered_spell_id = 48504;
5347 basepoints0 = triggerAmount * damage / 100;
5348 break;
5350 break;
5352 case SPELLFAMILY_ROGUE:
5354 switch(dummySpell->Id)
5356 // Deadly Throw Interrupt
5357 case 32748:
5359 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5360 if(this == pVictim)
5361 return false;
5363 triggered_spell_id = 32747;
5364 break;
5367 // Cut to the Chase
5368 if( dummySpell->SpellIconID == 2909 )
5370 // "refresh your Slice and Dice duration to its 5 combo point maximum"
5371 // lookup Slice and Dice
5372 AuraList const& sd = GetAurasByType(SPELL_AURA_MOD_HASTE);
5373 for(AuraList::const_iterator itr = sd.begin(); itr != sd.end(); ++itr)
5375 SpellEntry const *spellProto = (*itr)->GetSpellProto();
5376 if (spellProto->SpellFamilyName == SPELLFAMILY_ROGUE &&
5377 (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000040000)))
5379 (*itr)->SetAuraMaxDuration(GetSpellMaxDuration(spellProto));
5380 (*itr)->RefreshAura();
5381 return true;
5384 return false;
5386 // Deadly Brew
5387 if( dummySpell->SpellIconID == 2963 )
5389 triggered_spell_id = 25809;
5390 break;
5392 // Quick Recovery
5393 if( dummySpell->SpellIconID == 2116 )
5395 if(!procSpell)
5396 return false;
5398 // energy cost save
5399 basepoints0 = procSpell->manaCost * triggerAmount/100;
5400 if(basepoints0 <= 0)
5401 return false;
5403 target = this;
5404 triggered_spell_id = 31663;
5405 break;
5407 break;
5409 case SPELLFAMILY_HUNTER:
5411 // Aspect of the Viper
5412 if (dummySpell->SpellFamilyFlags & UI64LIT(0x4000000000000))
5414 uint32 maxmana = GetMaxPower(POWER_MANA);
5415 basepoints0 = maxmana* GetAttackTime(RANGED_ATTACK)/1000.0f/100.0f;
5417 target = this;
5418 triggered_spell_id = 34075;
5419 break;
5421 // Thrill of the Hunt
5422 if (dummySpell->SpellIconID == 2236)
5424 if(!procSpell)
5425 return false;
5427 // mana cost save
5428 int32 mana = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
5429 basepoints0 = mana * 40/100;
5430 if(basepoints0 <= 0)
5431 return false;
5433 target = this;
5434 triggered_spell_id = 34720;
5435 break;
5437 // Hunting Party
5438 if ( dummySpell->SpellIconID == 3406 )
5440 triggered_spell_id = 57669;
5441 target = this;
5442 break;
5444 // Lock and Load
5445 if ( dummySpell->SpellIconID == 3579 )
5447 // Proc only from periodic (from trap activation proc another aura of this spell)
5448 if (!(procFlag & PROC_FLAG_ON_DO_PERIODIC) || !roll_chance_i(triggerAmount))
5449 return false;
5450 triggered_spell_id = 56453;
5451 target = this;
5452 break;
5454 // Rapid Recuperation
5455 if ( dummySpell->SpellIconID == 3560 )
5457 // This effect only from Rapid Killing (mana regen)
5458 if (!(procSpell->SpellFamilyFlags & UI64LIT(0x0100000000000000)))
5459 return false;
5460 triggered_spell_id = 56654;
5461 target = this;
5462 break;
5464 break;
5466 case SPELLFAMILY_PALADIN:
5468 // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
5469 if ((dummySpell->SpellFamilyFlags & UI64LIT(0x000000008000000)) && effIndex==0)
5471 triggered_spell_id = 25742;
5472 float ap = GetTotalAttackPowerValue(BASE_ATTACK);
5473 int32 holy = SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
5474 SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, pVictim);
5475 basepoints0 = GetAttackTime(BASE_ATTACK) * int32(ap*0.022f + 0.044f * holy) / 1000;
5476 break;
5478 // Sacred Shield
5479 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0008000000000000))
5481 triggered_spell_id = 58597;
5482 target = this;
5483 break;
5485 // Righteous Vengeance
5486 if (dummySpell->SpellIconID == 3025)
5488 // 4 damage tick
5489 basepoints0 = triggerAmount*damage/400;
5490 triggered_spell_id = 61840;
5491 break;
5493 // Sheath of Light
5494 if (dummySpell->SpellIconID == 3030)
5496 // 4 healing tick
5497 basepoints0 = triggerAmount*damage/400;
5498 triggered_spell_id = 54203;
5499 break;
5501 switch(dummySpell->Id)
5503 // Judgement of Light
5504 case 20185:
5506 // Get judgement caster
5507 Unit *caster = triggeredByAura->GetCaster();
5508 if (!caster)
5509 return false;
5510 float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
5511 int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
5512 caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this);
5513 basepoints0 = int32(ap*0.10f + 0.10f*holy);
5514 pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
5515 return true;
5517 // Judgement of Wisdom
5518 case 20186:
5520 if (pVictim->getPowerType() == POWER_MANA)
5522 // 2% of maximum base mana
5523 basepoints0 = int32(pVictim->GetCreateMana() * 2 / 100);
5524 pVictim->CastCustomSpell(pVictim, 20268, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
5526 return true;
5528 // Holy Power (Redemption Armor set)
5529 case 28789:
5531 if(!pVictim)
5532 return false;
5534 // Set class defined buff
5535 switch (pVictim->getClass())
5537 case CLASS_PALADIN:
5538 case CLASS_PRIEST:
5539 case CLASS_SHAMAN:
5540 case CLASS_DRUID:
5541 triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5542 break;
5543 case CLASS_MAGE:
5544 case CLASS_WARLOCK:
5545 triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5546 break;
5547 case CLASS_HUNTER:
5548 case CLASS_ROGUE:
5549 triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
5550 break;
5551 case CLASS_WARRIOR:
5552 triggered_spell_id = 28790; // Increases the friendly target's armor
5553 break;
5554 default:
5555 return false;
5557 break;
5559 case 25899: // Greater Blessing of Sanctuary
5560 case 20911: // Blessing of Sanctuary
5562 if (target->GetTypeId() != TYPEID_PLAYER)
5563 return false;
5565 target = this;
5566 switch (target->getPowerType())
5568 case POWER_MANA:
5569 triggered_spell_id = 57319;
5570 break;
5571 default:
5572 return false;
5574 break;
5576 // Seal of Vengeance (damage calc on apply aura)
5577 case 31801:
5579 if(effIndex != 0) // effect 1,2 used by seal unleashing code
5580 return false;
5582 triggered_spell_id = 31803;
5583 break;
5585 // Spiritual Attunement
5586 case 31785:
5587 case 33776:
5589 // if healed by another unit (pVictim)
5590 if(this == pVictim)
5591 return false;
5593 // heal amount
5594 basepoints0 = triggerAmount*damage/100;
5595 target = this;
5596 triggered_spell_id = 31786;
5597 break;
5599 // Seal of Blood do damage trigger
5600 case 31892:
5602 if (effIndex == 0) // 0 effect - is proc on enemy
5603 triggered_spell_id = 31893;
5604 else if (effIndex == 1) // 1 effect - is proc on self
5606 // add spell damage from prev effect (27%)
5607 damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100;
5608 basepoints0 = triggerAmount * damage / 100;
5609 target = this;
5610 triggered_spell_id = 32221;
5612 else
5613 return true;
5614 break;
5616 // Seal of the Martyr do damage trigger
5617 case 53720:
5619 if (effIndex == 0) // 0 effect - is proc on enemy
5620 triggered_spell_id = 53719;
5621 else if (effIndex == 1) // 1 effect - is proc on self
5623 // add spell damage from prev effect (27%)
5624 damage += CalculateDamage(BASE_ATTACK, false) * 27 / 100;
5625 basepoints0 = triggerAmount * damage / 100;
5626 target = this;
5627 triggered_spell_id = 53718;
5629 else
5630 return true;
5631 break;
5633 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5634 case 40470:
5636 if (!procSpell)
5637 return false;
5639 float chance;
5641 // Flash of light/Holy light
5642 if (procSpell->SpellFamilyFlags & UI64LIT(0x00000000C0000000))
5644 triggered_spell_id = 40471;
5645 chance = 15.0f;
5647 // Judgement
5648 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000800000))
5650 triggered_spell_id = 40472;
5651 chance = 50.0f;
5653 else
5654 return false;
5656 if (!roll_chance_f(chance))
5657 return false;
5659 break;
5661 // Glyph of Divinity
5662 case 54939:
5664 // Lookup base amount mana restore
5665 for (int i=0; i<3;++i)
5666 if (procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
5668 int32 mana = procSpell->EffectBasePoints[i];
5669 CastCustomSpell(this, 54986, NULL, &mana, NULL, true, castItem, triggeredByAura);
5670 break;
5672 return true;
5674 // Glyph of Flash of Light
5675 case 54936:
5677 triggered_spell_id = 54957;
5678 basepoints0 = triggerAmount*damage/100;
5679 break;
5681 // Glyph of Holy Light
5682 case 54937:
5684 triggered_spell_id = 54968;
5685 basepoints0 = triggerAmount*damage/100;
5686 break;
5689 break;
5691 case SPELLFAMILY_SHAMAN:
5693 switch(dummySpell->Id)
5695 // Totemic Power (The Earthshatterer set)
5696 case 28823:
5698 if( !pVictim )
5699 return false;
5701 // Set class defined buff
5702 switch (pVictim->getClass())
5704 case CLASS_PALADIN:
5705 case CLASS_PRIEST:
5706 case CLASS_SHAMAN:
5707 case CLASS_DRUID:
5708 triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5709 break;
5710 case CLASS_MAGE:
5711 case CLASS_WARLOCK:
5712 triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5713 break;
5714 case CLASS_HUNTER:
5715 case CLASS_ROGUE:
5716 triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
5717 break;
5718 case CLASS_WARRIOR:
5719 triggered_spell_id = 28827; // Increases the friendly target's armor
5720 break;
5721 default:
5722 return false;
5724 break;
5726 // Lesser Healing Wave (Totem of Flowing Water Relic)
5727 case 28849:
5729 target = this;
5730 triggered_spell_id = 28850;
5731 break;
5733 // Windfury Weapon (Passive) 1-5 Ranks
5734 case 33757:
5736 if(GetTypeId()!=TYPEID_PLAYER)
5737 return false;
5739 if(!castItem || !castItem->IsEquipped())
5740 return false;
5742 // custom cooldown processing case
5743 if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
5744 return false;
5746 // Now amount of extra power stored in 1 effect of Enchant spell
5747 // Get it by item enchant id
5748 uint32 spellId;
5749 switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
5751 case 283: spellId = 8232; break; // 1 Rank
5752 case 284: spellId = 8235; break; // 2 Rank
5753 case 525: spellId = 10486; break; // 3 Rank
5754 case 1669:spellId = 16362; break; // 4 Rank
5755 case 2636:spellId = 25505; break; // 5 Rank
5756 case 3785:spellId = 58801; break; // 6 Rank
5757 case 3786:spellId = 58803; break; // 7 Rank
5758 case 3787:spellId = 58804; break; // 8 Rank
5759 default:
5761 sLog.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5762 castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)),dummySpell->Id);
5763 return false;
5767 SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId);
5768 if(!windfurySpellEntry)
5770 sLog.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId);
5771 return false;
5774 int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim);
5776 // Off-Hand case
5777 if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND )
5779 // Value gained from additional AP
5780 basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
5781 triggered_spell_id = 33750;
5783 // Main-Hand case
5784 else
5786 // Value gained from additional AP
5787 basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000);
5788 triggered_spell_id = 25504;
5791 // apply cooldown before cast to prevent processing itself
5792 if( cooldown )
5793 ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown);
5795 // Attack Twice
5796 for ( uint32 i = 0; i<2; ++i )
5797 CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
5799 return true;
5801 // Shaman Tier 6 Trinket
5802 case 40463:
5804 if( !procSpell )
5805 return false;
5807 float chance;
5808 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000001))
5810 triggered_spell_id = 40465; // Lightning Bolt
5811 chance = 15.0f;
5813 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000080))
5815 triggered_spell_id = 40465; // Lesser Healing Wave
5816 chance = 10.0f;
5818 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000001000000000))
5820 triggered_spell_id = 40466; // Stormstrike
5821 chance = 50.0f;
5823 else
5824 return false;
5826 if (!roll_chance_f(chance))
5827 return false;
5829 target = this;
5830 break;
5832 // Glyph of Healing Wave
5833 case 55440:
5835 // Not proc from self heals
5836 if (this==pVictim)
5837 return false;
5838 basepoints0 = triggerAmount * damage / 100;
5839 target = this;
5840 triggered_spell_id = 55533;
5841 break;
5843 // Spirit Hunt
5844 case 58877:
5846 // Cast on owner
5847 target = GetOwner();
5848 if(!target)
5849 return false;
5850 basepoints0 = triggerAmount * damage / 100;
5851 triggered_spell_id = 58879;
5852 break;
5855 // Storm, Earth and Fire
5856 if (dummySpell->SpellIconID == 3063)
5858 // Earthbind Totem summon only
5859 if(procSpell->Id != 2484)
5860 return false;
5862 float chance = triggerAmount;
5863 if (!roll_chance_f(chance))
5864 return false;
5866 triggered_spell_id = 64695;
5867 break;
5869 // Ancestral Awakening
5870 if (dummySpell->SpellIconID == 3065)
5872 triggered_spell_id = 52759;
5873 basepoints0 = triggerAmount * damage / 100;
5874 target = this;
5875 break;
5877 // Earth Shield
5878 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000040000000000))
5880 basepoints0 = triggerAmount;
5881 target = this;
5882 triggered_spell_id = 379;
5883 break;
5885 // Improved Water Shield
5886 if (dummySpell->SpellIconID == 2287)
5888 // Lesser Healing Wave need aditional 60% roll
5889 if ((procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000080)) && !roll_chance_i(60))
5890 return false;
5891 // lookup water shield
5892 AuraList const& vs = GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
5893 for(AuraList::const_iterator itr = vs.begin(); itr != vs.end(); ++itr)
5895 if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN &&
5896 ((*itr)->GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000002000000000)))
5898 uint32 spell = (*itr)->GetSpellProto()->EffectTriggerSpell[(*itr)->GetEffIndex()];
5899 CastSpell(this, spell, true, castItem, triggeredByAura);
5900 if ((*itr)->DropAuraCharge())
5901 RemoveAurasDueToSpell((*itr)->GetId());
5902 return true;
5905 return false;
5906 break;
5908 // Lightning Overload
5909 if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5911 if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim )
5912 return false;
5914 // custom cooldown processing case
5915 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
5916 return false;
5918 uint32 spellId = 0;
5919 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5920 switch (procSpell->Id)
5922 // Lightning Bolt
5923 case 403: spellId = 45284; break; // Rank 1
5924 case 529: spellId = 45286; break; // Rank 2
5925 case 548: spellId = 45287; break; // Rank 3
5926 case 915: spellId = 45288; break; // Rank 4
5927 case 943: spellId = 45289; break; // Rank 5
5928 case 6041: spellId = 45290; break; // Rank 6
5929 case 10391: spellId = 45291; break; // Rank 7
5930 case 10392: spellId = 45292; break; // Rank 8
5931 case 15207: spellId = 45293; break; // Rank 9
5932 case 15208: spellId = 45294; break; // Rank 10
5933 case 25448: spellId = 45295; break; // Rank 11
5934 case 25449: spellId = 45296; break; // Rank 12
5935 case 49237: spellId = 49239; break; // Rank 13
5936 case 49238: spellId = 49240; break; // Rank 14
5937 // Chain Lightning
5938 case 421: spellId = 45297; break; // Rank 1
5939 case 930: spellId = 45298; break; // Rank 2
5940 case 2860: spellId = 45299; break; // Rank 3
5941 case 10605: spellId = 45300; break; // Rank 4
5942 case 25439: spellId = 45301; break; // Rank 5
5943 case 25442: spellId = 45302; break; // Rank 6
5944 case 49268: spellId = 49270; break; // Rank 7
5945 case 49269: spellId = 49271; break; // Rank 8
5946 default:
5947 sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
5948 return false;
5950 // No thread generated mod
5951 // TODO: exist special flag in spell attributes for this, need found and use!
5952 SpellModifier *mod = new SpellModifier;
5953 mod->op = SPELLMOD_THREAT;
5954 mod->value = -100;
5955 mod->type = SPELLMOD_PCT;
5956 mod->spellId = dummySpell->Id;
5957 mod->mask = UI64LIT(0x0000000000000003);
5958 mod->mask2= UI64LIT(0x0);
5959 ((Player*)this)->AddSpellMod(mod, true);
5961 // Remove cooldown (Chain Lightning - have Category Recovery time)
5962 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000002))
5963 ((Player*)this)->RemoveSpellCooldown(spellId);
5965 CastSpell(pVictim, spellId, true, castItem, triggeredByAura);
5967 ((Player*)this)->AddSpellMod(mod, false);
5969 if( cooldown && GetTypeId()==TYPEID_PLAYER )
5970 ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown);
5972 return true;
5974 // Static Shock
5975 if(dummySpell->SpellIconID == 3059)
5977 // lookup Lightning Shield
5978 AuraList const& vs = GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
5979 for(AuraList::const_iterator itr = vs.begin(); itr != vs.end(); ++itr)
5981 if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN &&
5982 ((*itr)->GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000400)))
5984 uint32 spell = 0;
5985 switch ((*itr)->GetId())
5987 case 324: spell = 26364; break;
5988 case 325: spell = 26365; break;
5989 case 905: spell = 26366; break;
5990 case 945: spell = 26367; break;
5991 case 8134: spell = 26369; break;
5992 case 10431: spell = 26370; break;
5993 case 10432: spell = 26363; break;
5994 case 25469: spell = 26371; break;
5995 case 25472: spell = 26372; break;
5996 case 49280: spell = 49278; break;
5997 case 49281: spell = 49279; break;
5998 default:
5999 return false;
6001 CastSpell(target, spell, true, castItem, triggeredByAura);
6002 if ((*itr)->DropAuraCharge())
6003 RemoveAurasDueToSpell((*itr)->GetId());
6004 return true;
6007 return false;
6008 break;
6010 break;
6012 case SPELLFAMILY_DEATHKNIGHT:
6014 // Blood Aura
6015 if (dummySpell->SpellIconID == 2636)
6017 if (GetTypeId() != TYPEID_PLAYER || !((Player*)this)->isHonorOrXPTarget(pVictim))
6018 return false;
6019 basepoints0 = triggerAmount * damage / 100;
6020 triggered_spell_id = 53168;
6021 break;
6023 // Butchery
6024 if (dummySpell->SpellIconID == 2664)
6026 basepoints0 = triggerAmount;
6027 triggered_spell_id = 50163;
6028 target = this;
6029 break;
6031 // Dancing Rune Weapon
6032 if (dummySpell->Id == 49028)
6034 // 1 dummy aura for dismiss rune blade
6035 if (effIndex!=2)
6036 return false;
6037 // TODO: wite script for this "fights on its own, doing the same attacks"
6038 // NOTE: Trigger here on every attack and spell cast
6039 return false;
6041 // Mark of Blood
6042 if (dummySpell->Id == 49005)
6044 // TODO: need more info (cooldowns/PPM)
6045 triggered_spell_id = 61607;
6046 break;
6048 // Vendetta
6049 if (dummySpell->SpellFamilyFlags & UI64LIT(0x0000000000010000))
6051 basepoints0 = triggerAmount * GetMaxHealth() / 100;
6052 triggered_spell_id = 50181;
6053 target = this;
6054 break;
6056 // Necrosis
6057 if (dummySpell->SpellIconID == 2709)
6059 basepoints0 = triggerAmount * damage / 100;
6060 triggered_spell_id = 51460;
6061 break;
6063 // Runic Power Back on Snare/Root
6064 if (dummySpell->Id == 61257)
6066 // only for spells and hit/crit (trigger start always) and not start from self casted spells
6067 if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
6068 return false;
6069 // Need snare or root mechanic
6070 if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_SNARE))))
6071 return false;
6072 triggered_spell_id = 61258;
6073 target = this;
6074 break;
6076 // Wandering Plague
6077 if (dummySpell->SpellIconID == 1614)
6079 if (!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, pVictim)))
6080 return false;
6081 basepoints0 = triggerAmount * damage / 100;
6082 triggered_spell_id = 50526;
6083 break;
6085 break;
6087 default:
6088 break;
6091 // processed charge only counting case
6092 if(!triggered_spell_id)
6093 return true;
6095 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
6097 if(!triggerEntry)
6099 sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
6100 return false;
6103 // default case
6104 if(!target || target!=this && !target->isAlive())
6105 return false;
6107 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
6108 return false;
6110 if(basepoints0)
6111 CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
6112 else
6113 CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
6115 if( cooldown && GetTypeId()==TYPEID_PLAYER )
6116 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
6118 return true;
6121 bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
6123 // Get triggered aura spell info
6124 SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
6126 // Basepoints of trigger aura
6127 int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
6129 // Set trigger spell id, target, custom basepoints
6130 uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
6131 Unit* target = NULL;
6132 int32 basepoints0 = 0;
6134 if(triggeredByAura->GetModifier()->m_auraname == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
6135 basepoints0 = triggerAmount;
6137 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6138 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
6140 // Try handle uncnown trigger spells
6141 if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
6143 switch (auraSpellInfo->SpellFamilyName)
6145 case SPELLFAMILY_GENERIC:
6146 //if (auraSpellInfo->Id==59532) // Abandon Passengers on Poly
6147 //if (auraSpellInfo->Id==54775) // Abandon Vehicle on Poly
6148 //if (auraSpellInfo->Id==34082) // Advantaged State (DND)
6149 if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket)
6150 trigger_spell_id = 23781;
6151 //else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
6152 //else if (auraSpellInfo->Id == 48876) // Beast's Mark
6154 // trigger_spell_id = 48877;
6156 //else if (auraSpellInfo->Id == 59237) // Beast's Mark
6158 // trigger_spell_id = 59233;
6160 //else if (auraSpellInfo->Id==46939) // Black Bow of the Betrayer
6162 // trigger_spell_id = 29471; // gain mana
6163 // 27526; // drain mana if possible
6165 //else if (auraSpellInfo->Id==50844) // Blood Mirror
6166 //else if (auraSpellInfo->Id==54476) // Blood Presence
6167 //else if (auraSpellInfo->Id==50689) // Blood Presence (Rank 1)
6168 //else if (auraSpellInfo->Id==37030) // Chaotic Temperament
6169 //else if (auraSpellInfo->Id==52856) // Charge
6170 else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
6172 // Pct value stored in dummy
6173 basepoints0 = pVictim->GetCreateHealth() * auraSpellInfo->EffectBasePoints[1] / 100;
6174 target = pVictim;
6175 break;
6177 //else if (auraSpellInfo->Id==41248) // Consuming Strikes
6178 // trigger_spell_id = 41249;
6179 //else if (auraSpellInfo->Id==45205) // Copy Offhand Weapon
6180 //else if (auraSpellInfo->Id==57594) // Copy Ranged Weapon
6181 //else if (auraSpellInfo->Id==41054) // Copy Weapon
6182 // trigger_spell_id = 41055;
6183 //else if (auraSpellInfo->Id==45343) // Dark Flame Aura
6184 //else if (auraSpellInfo->Id==47300) // Dark Flame Aura
6185 else if (auraSpellInfo->Id==57345) // Darkmoon Card: Greatness
6187 float stat = 0.0f;
6188 // strength
6189 if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229;stat = GetStat(STAT_STRENGTH); }
6190 // agility
6191 if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233;stat = GetStat(STAT_AGILITY); }
6192 // intellect
6193 if (GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234;stat = GetStat(STAT_INTELLECT);}
6194 // spirit
6195 if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235;stat = GetStat(STAT_SPIRIT); }
6197 //else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1)
6198 //else if (auraSpellInfo->Id==5301) // Defensive State (DND)
6199 //else if (auraSpellInfo->Id==13358) // Defensive State (DND)
6200 //else if (auraSpellInfo->Id==16092) // Defensive State (DND)
6201 //else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND)
6202 //else if (auraSpellInfo->Id==40329) // Demo Shout Sensor
6203 else if (auraSpellInfo->Id == 33896) // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
6204 trigger_spell_id = 33898;
6205 //else if (auraSpellInfo->Id==18943) // Double Attack
6206 //else if (auraSpellInfo->Id==19194) // Double Attack
6207 //else if (auraSpellInfo->Id==19817) // Double Attack
6208 //else if (auraSpellInfo->Id==19818) // Double Attack
6209 //else if (auraSpellInfo->Id==22835) // Drunken Rage
6210 // trigger_spell_id = 14822;
6212 else if (auraSpellInfo->SpellIconID==191) // Elemental Response
6214 switch (auraSpellInfo->Id && auraSpellInfo->AttributesEx==0)
6216 case 34191:
6217 case 34329:
6218 case 34524:
6219 case 34582:
6220 case 36733:
6221 break;
6222 default:
6223 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",auraSpellInfo->Id);
6224 return false;
6226 //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
6227 switch (procSpell->School)
6229 case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192; break;
6230 case SPELL_SCHOOL_FROST: trigger_spell_id = 34193; break;
6231 case SPELL_SCHOOL_ARCANE:trigger_spell_id = 34194; break;
6232 case SPELL_SCHOOL_NATURE:trigger_spell_id = 34195; break;
6233 case SPELL_SCHOOL_SHADOW:trigger_spell_id = 34196; break;
6234 case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197; break;
6235 case SPELL_SCHOOL_NORMAL:trigger_spell_id = 34198; break;
6236 default:
6237 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id);
6238 return false;
6242 //else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor
6243 //else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget
6244 //else if (auraSpellInfo->Id==50051) // Ethereal Pet Aura
6245 //else if (auraSpellInfo->Id==35321) // Gushing Wound
6246 //else if (auraSpellInfo->Id==38363) // Gushing Wound
6247 //else if (auraSpellInfo->Id==39215) // Gushing Wound
6248 //else if (auraSpellInfo->Id==44527) // Hate Monster (Spar Buddy) (30 sec)
6249 //else if (auraSpellInfo->Id==44819) // Hate Monster (Spar Buddy) (>30% Health)
6250 //else if (auraSpellInfo->Id==44526) // Hate Monster (Spar) (30 sec)
6251 //else if (auraSpellInfo->Id==44820) // Hate Monster (Spar) (<30%)
6252 //else if (auraSpellInfo->Id==49059) // Horde, Hate Monster (Spar Buddy) (>30% Health)
6253 //else if (auraSpellInfo->Id==40250) // Improved Duration
6254 //else if (auraSpellInfo->Id==59288) // Infra-Green Shield
6255 //else if (auraSpellInfo->Id==54072) // Knockback Ball Passive
6256 else if (auraSpellInfo->Id==27522 || auraSpellInfo->Id==40336)
6257 // Mana Drain Trigger
6259 // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
6260 if (this && this->isAlive())
6261 CastSpell(this, 29471, true, castItem, triggeredByAura);
6262 if (pVictim && pVictim->isAlive())
6263 CastSpell(pVictim, 27526, true, castItem, triggeredByAura);
6264 return true;
6266 //else if (auraSpellInfo->Id==55580) // Mana Link
6267 //else if (auraSpellInfo->Id==45903) // Offensive State
6268 //else if (auraSpellInfo->Id==44326) // Pure Energy Passive
6269 //else if (auraSpellInfo->Id==43453) // Rune Ward
6270 //else if (auraSpellInfo->Id== 7137) // Shadow Charge (Rank 1)
6271 //else if (auraSpellInfo->Id==36576) // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger
6272 //else if (auraSpellInfo->Id==34783) // Spell Reflection
6273 //else if (auraSpellInfo->Id==36096) // Spell Reflection
6274 //else if (auraSpellInfo->Id==57587) // Steal Ranged ()
6275 //else if (auraSpellInfo->Id==36207) // Steal Weapon
6276 //else if (auraSpellInfo->Id== 7377) // Take Immune Periodic Damage <Not Working>
6277 //else if (auraSpellInfo->Id==35205) // Vanish
6278 //else if (auraSpellInfo->Id==42730) // Woe Strike
6279 //else if (auraSpellInfo->Id==59735) // Woe Strike
6280 //else if (auraSpellInfo->Id==46146) // [PH] Ahune Spanky Hands
6281 break;
6282 case SPELLFAMILY_MAGE:
6283 if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed
6285 switch (auraSpellInfo->Id)
6287 case 31641: // Rank 1
6288 case 31642: // Rank 2
6289 trigger_spell_id = 31643;
6290 break;
6291 default:
6292 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed",auraSpellInfo->Id);
6293 return false;
6296 break;
6297 case SPELLFAMILY_WARRIOR:
6298 if (auraSpellInfo->Id == 50421) // Scent of Blood
6299 trigger_spell_id = 50422;
6300 break;
6301 case SPELLFAMILY_WARLOCK:
6303 // Pyroclasm
6304 if (auraSpellInfo->SpellIconID == 1137)
6306 if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
6307 return false;
6308 // Calculate spell tick count for spells
6309 uint32 tick = 1; // Default tick = 1
6311 // Hellfire have 15 tick
6312 if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000040))
6313 tick = 15;
6314 // Rain of Fire have 4 tick
6315 else if (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000020))
6316 tick = 4;
6317 else
6318 return false;
6320 // Calculate chance = baseChance / tick
6321 float chance = 0;
6322 switch (auraSpellInfo->Id)
6324 case 18096: chance = 13.0f / tick; break;
6325 case 18073: chance = 26.0f / tick; break;
6327 // Roll chance
6328 if (!roll_chance_f(chance))
6329 return false;
6331 trigger_spell_id = 18093;
6333 // Drain Soul
6334 else if (auraSpellInfo->SpellFamilyFlags & UI64LIT(0x0000000000004000))
6336 Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
6337 for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
6339 if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
6341 int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
6342 // Drain Soul
6343 CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
6344 break;
6347 // Not remove charge (aura removed on death in any cases)
6348 // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
6349 return false;
6351 // Nether Protection
6352 else if (auraSpellInfo->SpellIconID == 1985)
6354 if (!procSpell)
6355 return false;
6356 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
6358 case SPELL_SCHOOL_NORMAL:
6359 return false; // ignore
6360 case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break;
6361 case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break;
6362 case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break;
6363 case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break;
6364 case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break;
6365 case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
6366 default:
6367 return false;
6370 break;
6372 case SPELLFAMILY_PRIEST:
6374 // Greater Heal Refund
6375 if (auraSpellInfo->Id==37594)
6376 trigger_spell_id = 37595;
6377 // Blessed Recovery
6378 else if (auraSpellInfo->SpellIconID == 1875)
6380 switch (auraSpellInfo->Id)
6382 case 27811: trigger_spell_id = 27813; break;
6383 case 27815: trigger_spell_id = 27817; break;
6384 case 27816: trigger_spell_id = 27818; break;
6385 default:
6386 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
6387 return false;
6389 basepoints0 = damage * triggerAmount / 100 / 3;
6390 target = this;
6392 break;
6394 case SPELLFAMILY_DRUID:
6396 // Druid Forms Trinket
6397 if (auraSpellInfo->Id==37336)
6399 switch(m_form)
6401 case FORM_NONE: trigger_spell_id = 37344;break;
6402 case FORM_CAT: trigger_spell_id = 37341;break;
6403 case FORM_BEAR:
6404 case FORM_DIREBEAR: trigger_spell_id = 37340;break;
6405 case FORM_TREE: trigger_spell_id = 37342;break;
6406 case FORM_MOONKIN: trigger_spell_id = 37343;break;
6407 default:
6408 return false;
6411 //else if (auraSpellInfo->Id==40363)// Entangling Roots ()
6412 // trigger_spell_id = ????;
6413 // Leader of the Pack
6414 else if (auraSpellInfo->Id == 24932)
6416 if (triggerAmount == 0)
6417 return false;
6418 basepoints0 = triggerAmount * GetMaxHealth() / 100;
6419 trigger_spell_id = 34299;
6421 break;
6423 case SPELLFAMILY_HUNTER:
6424 break;
6425 case SPELLFAMILY_PALADIN:
6428 // Blessed Life
6429 if (auraSpellInfo->SpellIconID == 2137)
6431 switch (auraSpellInfo->Id)
6433 case 31828: // Rank 1
6434 case 31829: // Rank 2
6435 case 31830: // Rank 3
6436 break;
6437 default:
6438 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life", auraSpellInfo->Id);
6439 return false;
6443 // Healing Discount
6444 if (auraSpellInfo->Id==37705)
6446 trigger_spell_id = 37706;
6447 target = this;
6449 // Soul Preserver
6450 if (auraSpellInfo->Id==60510)
6452 trigger_spell_id = 60515;
6453 target = this;
6455 // Illumination
6456 else if (auraSpellInfo->SpellIconID==241)
6458 if(!procSpell)
6459 return false;
6460 // procspell is triggered spell but we need mana cost of original casted spell
6461 uint32 originalSpellId = procSpell->Id;
6462 // Holy Shock heal
6463 if (procSpell->SpellFamilyFlags & UI64LIT(0x0001000000000000))
6465 switch(procSpell->Id)
6467 case 25914: originalSpellId = 20473; break;
6468 case 25913: originalSpellId = 20929; break;
6469 case 25903: originalSpellId = 20930; break;
6470 case 27175: originalSpellId = 27174; break;
6471 case 33074: originalSpellId = 33072; break;
6472 case 48820: originalSpellId = 48824; break;
6473 case 48821: originalSpellId = 48825; break;
6474 default:
6475 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
6476 return false;
6479 SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
6480 if(!originalSpell)
6482 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
6483 return false;
6485 // percent stored in effect 1 (class scripts) base points
6486 int32 cost = originalSpell->manaCost + originalSpell->ManaCostPercentage * GetCreateMana() / 100;
6487 basepoints0 = cost*auraSpellInfo->CalculateSimpleValue(1)/100;
6488 trigger_spell_id = 20272;
6489 target = this;
6491 // Lightning Capacitor
6492 else if (auraSpellInfo->Id==37657)
6494 if(!pVictim || !pVictim->isAlive())
6495 return false;
6496 // stacking
6497 CastSpell(this, 37658, true, NULL, triggeredByAura);
6499 Aura * dummy = GetDummyAura(37658);
6500 // release at 3 aura in stack (cont contain in basepoint of trigger aura)
6501 if(!dummy || dummy->GetStackAmount() < triggerAmount)
6502 return false;
6504 RemoveAurasDueToSpell(37658);
6505 trigger_spell_id = 37661;
6506 target = pVictim;
6508 // Thunder Capacitor
6509 else if (auraSpellInfo->Id == 54841)
6511 if(!pVictim || !pVictim->isAlive())
6512 return false;
6513 // stacking
6514 CastSpell(this, 54842, true, NULL, triggeredByAura);
6516 // counting
6517 Aura * dummy = GetDummyAura(54842);
6518 // release at 3 aura in stack (cont contain in basepoint of trigger aura)
6519 if(!dummy || dummy->GetStackAmount() < triggerAmount)
6520 return false;
6522 RemoveAurasDueToSpell(54842);
6523 trigger_spell_id = 54843;
6524 target = pVictim;
6526 break;
6528 case SPELLFAMILY_SHAMAN:
6530 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc
6531 if (auraSpellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000400))
6533 switch(auraSpellInfo->Id)
6535 case 324: // Rank 1
6536 trigger_spell_id = 26364; break;
6537 case 325: // Rank 2
6538 trigger_spell_id = 26365; break;
6539 case 905: // Rank 3
6540 trigger_spell_id = 26366; break;
6541 case 945: // Rank 4
6542 trigger_spell_id = 26367; break;
6543 case 8134: // Rank 5
6544 trigger_spell_id = 26369; break;
6545 case 10431: // Rank 6
6546 trigger_spell_id = 26370; break;
6547 case 10432: // Rank 7
6548 trigger_spell_id = 26363; break;
6549 case 25469: // Rank 8
6550 trigger_spell_id = 26371; break;
6551 case 25472: // Rank 9
6552 trigger_spell_id = 26372; break;
6553 case 49280: // Rank 10
6554 trigger_spell_id = 49278; break;
6555 case 49281: // Rank 11
6556 trigger_spell_id = 49279; break;
6557 default:
6558 sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id);
6559 return false;
6562 // Lightning Shield (The Ten Storms set)
6563 else if (auraSpellInfo->Id == 23551)
6565 trigger_spell_id = 23552;
6566 target = pVictim;
6568 // Damage from Lightning Shield (The Ten Storms set)
6569 else if (auraSpellInfo->Id == 23552)
6570 trigger_spell_id = 27635;
6571 // Mana Surge (The Earthfury set)
6572 else if (auraSpellInfo->Id == 23572)
6574 if(!procSpell)
6575 return false;
6576 basepoints0 = procSpell->manaCost * 35 / 100;
6577 trigger_spell_id = 23571;
6578 target = this;
6580 // Nature's Guardian
6581 else if (auraSpellInfo->SpellIconID == 2013)
6583 // Check health condition - should drop to less 30% (damage deal after this!)
6584 if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth()))
6585 return false;
6587 if(pVictim && pVictim->isAlive())
6588 pVictim->getThreatManager().modifyThreatPercent(this,-10);
6590 basepoints0 = triggerAmount * GetMaxHealth() / 100;
6591 trigger_spell_id = 31616;
6592 target = this;
6594 break;
6596 case SPELLFAMILY_DEATHKNIGHT:
6598 // Acclimation
6599 if (auraSpellInfo->SpellIconID == 1930)
6601 if (!procSpell)
6602 return false;
6603 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
6605 case SPELL_SCHOOL_NORMAL:
6606 return false; // ignore
6607 case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break;
6608 case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break;
6609 case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break;
6610 case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
6611 case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break;
6612 case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
6613 default:
6614 return false;
6617 // Blood Presence
6618 else if (auraSpellInfo->Id == 48266)
6620 if (GetTypeId() != TYPEID_PLAYER)
6621 return false;
6622 if (!((Player*)this)->isHonorOrXPTarget(pVictim))
6623 return false;
6624 trigger_spell_id = 50475;
6625 basepoints0 = damage * triggerAmount / 100;
6627 break;
6629 default:
6630 break;
6634 // All ok. Check current trigger spell
6635 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
6636 if ( triggerEntry == NULL )
6638 // Not cast unknown spell
6639 // sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
6640 return false;
6643 // not allow proc extra attack spell at extra attack
6644 if( m_extraAttacks && IsSpellHaveEffect(triggerEntry, SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
6645 return false;
6647 // Custom requirements (not listed in procEx) Warning! damage dealing after this
6648 // Custom triggered spells
6649 switch (auraSpellInfo->Id)
6651 // Persistent Shield (Scarab Brooch trinket)
6652 // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
6653 case 26467:
6655 basepoints0 = damage * 15 / 100;
6656 target = pVictim;
6657 trigger_spell_id = 26470;
6658 break;
6660 // Cheat Death
6661 case 28845:
6663 // When your health drops below 20% ....
6664 if (GetHealth() - damage > GetMaxHealth() / 5 || GetHealth() < GetMaxHealth() / 5)
6665 return false;
6666 break;
6668 // Deadly Swiftness (Rank 1)
6669 case 31255:
6671 // whenever you deal damage to a target who is below 20% health.
6672 if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5)
6673 return false;
6675 target = this;
6676 trigger_spell_id = 22588;
6678 // Greater Heal Refund (Avatar Raiment set)
6679 case 37594:
6681 // Not give if target already have full health
6682 if (pVictim->GetHealth() == pVictim->GetMaxHealth())
6683 return false;
6684 // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
6685 if (pVictim->GetHealth() + damage < pVictim->GetMaxHealth())
6686 return false;
6687 break;
6689 // Bonus Healing (Crystal Spire of Karabor mace)
6690 case 40971:
6692 // If your target is below $s1% health
6693 if (pVictim->GetHealth() > pVictim->GetMaxHealth() * triggerAmount / 100)
6694 return false;
6695 break;
6697 // Evasive Maneuvers (Commendation of Kael`thas trinket)
6698 case 45057:
6700 // reduce you below $s1% health
6701 if (GetHealth() - damage > GetMaxHealth() * triggerAmount / 100)
6702 return false;
6703 break;
6705 // Rapid Recuperation
6706 case 53228:
6707 case 53232:
6709 // This effect only from Rapid Fire (ability cast)
6710 if (!(procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000020)))
6711 return false;
6712 break;
6716 // Custom basepoints/target for exist spell
6717 // dummy basepoints or other customs
6718 switch(trigger_spell_id)
6720 // Cast positive spell on enemy target
6721 case 7099: // Curse of Mending
6722 case 39647: // Curse of Mending
6723 case 29494: // Temptation
6724 case 20233: // Improved Lay on Hands (cast on target)
6726 target = pVictim;
6727 break;
6729 // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset)
6730 case 15250: // Rogue Setup
6732 if(!pVictim || pVictim != getVictim()) // applied only for main target
6733 return false;
6734 break; // continue normal case
6736 // Finish movies that add combo
6737 case 14189: // Seal Fate (Netherblade set)
6738 case 14157: // Ruthlessness
6740 // Need add combopoint AFTER finish movie (or they dropped in finish phase)
6741 break;
6743 // Bloodthirst (($m/100)% of max health)
6744 case 23880:
6746 basepoints0 = int32(GetMaxHealth() * triggerAmount / 100);
6747 break;
6749 // Shamanistic Rage triggered spell
6750 case 30824:
6752 basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100);
6753 break;
6755 // Enlightenment (trigger only from mana cost spells)
6756 case 35095:
6758 if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0)
6759 return false;
6760 break;
6762 // Brain Freeze
6763 case 57761:
6765 if(!procSpell)
6766 return false;
6767 // For trigger from Blizzard need exist Improved Blizzard
6768 if (procSpell->SpellFamilyName==SPELLFAMILY_MAGE && (procSpell->SpellFamilyFlags & UI64LIT(0x0000000000000080)))
6770 bool found = false;
6771 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
6772 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
6774 int32 script = (*i)->GetModifier()->m_miscvalue;
6775 if(script==836 || script==988 || script==989)
6777 found=true;
6778 break;
6781 if(!found)
6782 return false;
6784 break;
6786 // Astral Shift
6787 case 52179:
6789 if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
6790 return false;
6792 // Need stun, fear or silence mechanic
6793 if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR))))
6794 return false;
6795 break;
6797 // Burning Determination
6798 case 54748:
6800 if(!procSpell)
6801 return false;
6802 // Need Interrupt or Silenced mechanic
6803 if (!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE))))
6804 return false;
6805 break;
6807 // Lock and Load
6808 case 56453:
6810 // Proc only from trap activation (from periodic proc another aura of this spell)
6811 if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount))
6812 return false;
6813 break;
6817 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
6818 return false;
6820 // try detect target manually if not set
6821 if ( target == NULL )
6822 target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
6824 // default case
6825 if(!target || target!=this && !target->isAlive())
6826 return false;
6828 if(basepoints0)
6829 CastCustomSpell(target,trigger_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
6830 else
6831 CastSpell(target,trigger_spell_id,true,castItem,triggeredByAura);
6833 if( cooldown && GetTypeId()==TYPEID_PLAYER )
6834 ((Player*)this)->AddSpellCooldown(trigger_spell_id,0,time(NULL) + cooldown);
6836 return true;
6839 bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
6841 int32 scriptId = triggeredByAura->GetModifier()->m_miscvalue;
6843 if(!pVictim || !pVictim->isAlive())
6844 return false;
6846 Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6847 ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
6849 uint32 triggered_spell_id = 0;
6851 switch(scriptId)
6853 case 836: // Improved Blizzard (Rank 1)
6855 if (!procSpell || procSpell->SpellVisual[0]!=9487)
6856 return false;
6857 triggered_spell_id = 12484;
6858 break;
6860 case 988: // Improved Blizzard (Rank 2)
6862 if (!procSpell || procSpell->SpellVisual[0]!=9487)
6863 return false;
6864 triggered_spell_id = 12485;
6865 break;
6867 case 989: // Improved Blizzard (Rank 3)
6869 if (!procSpell || procSpell->SpellVisual[0]!=9487)
6870 return false;
6871 triggered_spell_id = 12486;
6872 break;
6874 case 4086: // Improved Mend Pet (Rank 1)
6875 case 4087: // Improved Mend Pet (Rank 2)
6877 int32 chance = triggeredByAura->GetSpellProto()->EffectBasePoints[triggeredByAura->GetEffIndex()];
6878 if(!roll_chance_i(chance))
6879 return false;
6881 triggered_spell_id = 24406;
6882 break;
6884 case 4533: // Dreamwalker Raiment 2 pieces bonus
6886 // Chance 50%
6887 if (!roll_chance_i(50))
6888 return false;
6890 switch (pVictim->getPowerType())
6892 case POWER_MANA: triggered_spell_id = 28722; break;
6893 case POWER_RAGE: triggered_spell_id = 28723; break;
6894 case POWER_ENERGY: triggered_spell_id = 28724; break;
6895 default:
6896 return false;
6898 break;
6900 case 4537: // Dreamwalker Raiment 6 pieces bonus
6901 triggered_spell_id = 28750; // Blessing of the Claw
6902 break;
6903 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6904 triggered_spell_id = 37445; // Mana Surge
6905 break;
6906 case 8152: // Serendipity
6908 // if heal your target over maximum health
6909 if (pVictim->GetHealth() + damage < pVictim->GetMaxHealth())
6910 return false;
6911 int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100;
6912 int32 basepoints0 = cost * triggeredByAura->GetModifier()->m_amount/100;
6913 CastCustomSpell(this, 47762, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
6914 return true;
6918 // not processed
6919 if(!triggered_spell_id)
6920 return false;
6922 // standard non-dummy case
6923 SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
6925 if(!triggerEntry)
6927 sLog.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id,scriptId);
6928 return false;
6931 if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
6932 return false;
6934 CastSpell(pVictim, triggered_spell_id, true, castItem, triggeredByAura);
6936 if( cooldown && GetTypeId()==TYPEID_PLAYER )
6937 ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
6939 return true;
6942 void Unit::setPowerType(Powers new_powertype)
6944 SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype);
6946 if(GetTypeId() == TYPEID_PLAYER)
6948 if(((Player*)this)->GetGroup())
6949 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
6951 else if(((Creature*)this)->isPet())
6953 Pet *pet = ((Pet*)this);
6954 if(pet->isControlled())
6956 Unit *owner = GetOwner();
6957 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
6958 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
6962 switch(new_powertype)
6964 default:
6965 case POWER_MANA:
6966 break;
6967 case POWER_RAGE:
6968 SetMaxPower(POWER_RAGE,GetCreatePowers(POWER_RAGE));
6969 SetPower( POWER_RAGE,0);
6970 break;
6971 case POWER_FOCUS:
6972 SetMaxPower(POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
6973 SetPower( POWER_FOCUS,GetCreatePowers(POWER_FOCUS));
6974 break;
6975 case POWER_ENERGY:
6976 SetMaxPower(POWER_ENERGY,GetCreatePowers(POWER_ENERGY));
6977 SetPower( POWER_ENERGY,0);
6978 break;
6979 case POWER_HAPPINESS:
6980 SetMaxPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
6981 SetPower(POWER_HAPPINESS,GetCreatePowers(POWER_HAPPINESS));
6982 break;
6986 FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
6988 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
6989 if(!entry)
6991 static uint64 guid = 0; // prevent repeating spam same faction problem
6993 if(GetGUID() != guid)
6995 if(GetTypeId() == TYPEID_PLAYER)
6996 sLog.outError("Player %s have invalid faction (faction template id) #%u", ((Player*)this)->GetName(), getFaction());
6997 else
6998 sLog.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature*)this)->GetCreatureInfo()->Entry, getFaction());
6999 guid = GetGUID();
7002 return entry;
7005 bool Unit::IsHostileTo(Unit const* unit) const
7007 // always non-hostile to self
7008 if(unit==this)
7009 return false;
7011 // always non-hostile to GM in GM mode
7012 if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
7013 return false;
7015 // always hostile to enemy
7016 if(getVictim()==unit || unit->getVictim()==this)
7017 return true;
7019 // test pet/charm masters instead pers/charmeds
7020 Unit const* testerOwner = GetCharmerOrOwner();
7021 Unit const* targetOwner = unit->GetCharmerOrOwner();
7023 // always hostile to owner's enemy
7024 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
7025 return true;
7027 // always hostile to enemy owner
7028 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
7029 return true;
7031 // always hostile to owner of owner's enemy
7032 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
7033 return true;
7035 Unit const* tester = testerOwner ? testerOwner : this;
7036 Unit const* target = targetOwner ? targetOwner : unit;
7038 // always non-hostile to target with common owner, or to owner/pet
7039 if(tester==target)
7040 return false;
7042 // special cases (Duel, etc)
7043 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
7045 Player const* pTester = (Player const*)tester;
7046 Player const* pTarget = (Player const*)target;
7048 // Duel
7049 if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0)
7050 return true;
7052 // Group
7053 if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup())
7054 return false;
7056 // Sanctuary
7057 if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
7058 return false;
7060 // PvP FFA state
7061 if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
7062 return true;
7064 //= PvP states
7065 // Green/Blue (can't attack)
7066 if(pTester->GetTeam()==pTarget->GetTeam())
7067 return false;
7069 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
7070 return pTester->IsPvP() && pTarget->IsPvP();
7073 // faction base cases
7074 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
7075 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
7076 if(!tester_faction || !target_faction)
7077 return false;
7079 if(target->isAttackingPlayer() && tester->IsContestedGuard())
7080 return true;
7082 // PvC forced reaction and reputation case
7083 if(tester->GetTypeId()==TYPEID_PLAYER)
7085 // forced reaction
7086 if(target_faction->faction)
7088 if(ReputationRank const* force =((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction))
7089 return *force <= REP_HOSTILE;
7091 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
7092 if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
7093 if(FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction))
7094 return (factionState->Flags & FACTION_FLAG_AT_WAR);
7097 // CvP forced reaction and reputation case
7098 else if(target->GetTypeId()==TYPEID_PLAYER)
7100 // forced reaction
7101 if(tester_faction->faction)
7103 if(ReputationRank const* force = ((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction))
7104 return *force <= REP_HOSTILE;
7106 // apply reputation state
7107 FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
7108 if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
7109 return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE;
7113 // common faction based case (CvC,PvC,CvP)
7114 return tester_faction->IsHostileTo(*target_faction);
7117 bool Unit::IsFriendlyTo(Unit const* unit) const
7119 // always friendly to self
7120 if(unit==this)
7121 return true;
7123 // always friendly to GM in GM mode
7124 if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
7125 return true;
7127 // always non-friendly to enemy
7128 if(getVictim()==unit || unit->getVictim()==this)
7129 return false;
7131 // test pet/charm masters instead pers/charmeds
7132 Unit const* testerOwner = GetCharmerOrOwner();
7133 Unit const* targetOwner = unit->GetCharmerOrOwner();
7135 // always non-friendly to owner's enemy
7136 if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner))
7137 return false;
7139 // always non-friendly to enemy owner
7140 if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this))
7141 return false;
7143 // always non-friendly to owner of owner's enemy
7144 if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner))
7145 return false;
7147 Unit const* tester = testerOwner ? testerOwner : this;
7148 Unit const* target = targetOwner ? targetOwner : unit;
7150 // always friendly to target with common owner, or to owner/pet
7151 if(tester==target)
7152 return true;
7154 // special cases (Duel)
7155 if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER)
7157 Player const* pTester = (Player const*)tester;
7158 Player const* pTarget = (Player const*)target;
7160 // Duel
7161 if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0)
7162 return false;
7164 // Group
7165 if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup())
7166 return true;
7168 // Sanctuary
7169 if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
7170 return true;
7172 // PvP FFA state
7173 if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
7174 return false;
7176 //= PvP states
7177 // Green/Blue (non-attackable)
7178 if(pTester->GetTeam()==pTarget->GetTeam())
7179 return true;
7181 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
7182 return !pTarget->IsPvP();
7185 // faction base cases
7186 FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
7187 FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
7188 if(!tester_faction || !target_faction)
7189 return false;
7191 if(target->isAttackingPlayer() && tester->IsContestedGuard())
7192 return false;
7194 // PvC forced reaction and reputation case
7195 if(tester->GetTypeId()==TYPEID_PLAYER)
7197 // forced reaction
7198 if(target_faction->faction)
7200 if(ReputationRank const* force =((Player*)tester)->GetReputationMgr().GetForcedRankIfAny(target_faction))
7201 return *force >= REP_FRIENDLY;
7203 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
7204 if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
7205 if(FactionState const* factionState = ((Player*)tester)->GetReputationMgr().GetState(raw_target_faction))
7206 return !(factionState->Flags & FACTION_FLAG_AT_WAR);
7209 // CvP forced reaction and reputation case
7210 else if(target->GetTypeId()==TYPEID_PLAYER)
7212 // forced reaction
7213 if(tester_faction->faction)
7215 if(ReputationRank const* force =((Player*)target)->GetReputationMgr().GetForcedRankIfAny(tester_faction))
7216 return *force >= REP_FRIENDLY;
7218 // apply reputation state
7219 if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
7220 if(raw_tester_faction->reputationListID >=0 )
7221 return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY;
7225 // common faction based case (CvC,PvC,CvP)
7226 return tester_faction->IsFriendlyTo(*target_faction);
7229 bool Unit::IsHostileToPlayers() const
7231 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
7232 if(!my_faction || !my_faction->faction)
7233 return false;
7235 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
7236 if(raw_faction && raw_faction->reputationListID >=0 )
7237 return false;
7239 return my_faction->IsHostileToPlayers();
7242 bool Unit::IsNeutralToAll() const
7244 FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
7245 if(!my_faction || !my_faction->faction)
7246 return true;
7248 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
7249 if(raw_faction && raw_faction->reputationListID >=0 )
7250 return false;
7252 return my_faction->IsNeutralToAll();
7255 bool Unit::Attack(Unit *victim, bool meleeAttack)
7257 if(!victim || victim == this)
7258 return false;
7260 // dead units can neither attack nor be attacked
7261 if(!isAlive() || !victim->isAlive())
7262 return false;
7264 // player cannot attack in mount state
7265 if(GetTypeId()==TYPEID_PLAYER && IsMounted())
7266 return false;
7268 // nobody can attack GM in GM-mode
7269 if(victim->GetTypeId()==TYPEID_PLAYER)
7271 if(((Player*)victim)->isGameMaster())
7272 return false;
7274 else
7276 if(((Creature*)victim)->IsInEvadeMode())
7277 return false;
7280 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
7281 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
7282 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE);
7284 // in fighting already
7285 if (m_attacking)
7287 if (m_attacking == victim)
7289 // switch to melee attack from ranged/magic
7290 if( meleeAttack && !hasUnitState(UNIT_STAT_MELEE_ATTACKING) )
7292 addUnitState(UNIT_STAT_MELEE_ATTACKING);
7293 SendMeleeAttackStart(victim);
7294 return true;
7296 return false;
7299 // remove old target data
7300 AttackStop(true);
7302 // new battle
7303 else
7305 // set position before any AI calls/assistance
7306 if(GetTypeId()==TYPEID_UNIT)
7307 ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
7310 //Set our target
7311 SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID());
7313 if(meleeAttack)
7314 addUnitState(UNIT_STAT_MELEE_ATTACKING);
7316 m_attacking = victim;
7317 m_attacking->_addAttacker(this);
7319 if(GetTypeId()==TYPEID_UNIT)
7321 WorldPacket data(SMSG_AI_REACTION, 12);
7322 data << uint64(GetGUID());
7323 data << uint32(AI_REACTION_AGGRO); // Aggro sound
7324 ((WorldObject*)this)->SendMessageToSet(&data, true);
7326 ((Creature*)this)->CallAssistance();
7329 // delay offhand weapon attack to next attack time
7330 if(haveOffhandWeapon())
7331 resetAttackTimer(OFF_ATTACK);
7333 if(meleeAttack)
7334 SendMeleeAttackStart(victim);
7336 return true;
7339 bool Unit::AttackStop(bool targetSwitch /*=false*/)
7341 if (!m_attacking)
7342 return false;
7344 Unit* victim = m_attacking;
7346 m_attacking->_removeAttacker(this);
7347 m_attacking = NULL;
7349 //Clear our target
7350 SetUInt64Value(UNIT_FIELD_TARGET, 0);
7352 clearUnitState(UNIT_STAT_MELEE_ATTACKING);
7354 InterruptSpell(CURRENT_MELEE_SPELL);
7356 // reset only at real combat stop
7357 if(!targetSwitch && GetTypeId()==TYPEID_UNIT )
7359 ((Creature*)this)->SetNoCallAssistance(false);
7360 ((Creature*)this)->SetNoSearchAssistance(false);
7363 SendMeleeAttackStop(victim);
7365 return true;
7368 void Unit::CombatStop(bool includingCast)
7370 if (includingCast && IsNonMeleeSpellCasted(false))
7371 InterruptNonMeleeSpells(false);
7373 AttackStop();
7374 RemoveAllAttackers();
7375 if( GetTypeId()==TYPEID_PLAYER )
7376 ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
7377 ClearInCombat();
7380 void Unit::CombatStopWithPets(bool includingCast)
7382 CombatStop(includingCast);
7383 if(Pet* pet = GetPet())
7384 pet->CombatStop(includingCast);
7385 if(Unit* charm = GetCharm())
7386 charm->CombatStop(includingCast);
7388 for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
7389 if(Unit* guardian = Unit::GetUnit(*this,*itr))
7390 guardian->CombatStop(includingCast);
7393 bool Unit::isAttackingPlayer() const
7395 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER))
7396 return true;
7398 Pet* pet = GetPet();
7399 if(pet && pet->isAttackingPlayer())
7400 return true;
7402 Unit* charmed = GetCharm();
7403 if(charmed && charmed->isAttackingPlayer())
7404 return true;
7406 for (int8 i = 0; i < MAX_TOTEM; ++i)
7408 if(m_TotemSlot[i])
7410 Creature *totem = GetMap()->GetCreature(m_TotemSlot[i]);
7411 if(totem && totem->isAttackingPlayer())
7412 return true;
7416 return false;
7419 void Unit::RemoveAllAttackers()
7421 while (!m_attackers.empty())
7423 AttackerSet::iterator iter = m_attackers.begin();
7424 if(!(*iter)->AttackStop())
7426 sLog.outError("WORLD: Unit has an attacker that isn't attacking it!");
7427 m_attackers.erase(iter);
7432 void Unit::ModifyAuraState(AuraState flag, bool apply)
7434 if (apply)
7436 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
7438 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
7439 if(GetTypeId() == TYPEID_PLAYER)
7441 const PlayerSpellMap& sp_list = ((Player*)this)->GetSpellMap();
7442 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
7444 if(itr->second->state == PLAYERSPELL_REMOVED) continue;
7445 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
7446 if (!spellInfo || !IsPassiveSpell(itr->first)) continue;
7447 if (spellInfo->CasterAuraState == flag)
7448 CastSpell(this, itr->first, true, NULL);
7453 else
7455 if (HasFlag(UNIT_FIELD_AURASTATE,1<<(flag-1)))
7457 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
7459 if (flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras
7461 Unit::AuraMap& tAuras = GetAuras();
7462 for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
7464 SpellEntry const* spellProto = (*itr).second->GetSpellProto();
7465 if (spellProto->CasterAuraState == flag)
7467 // exceptions (applied at state but not removed at state change)
7468 // Rampage
7469 if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags==0x100000)
7471 ++itr;
7472 continue;
7475 RemoveAura(itr);
7477 else
7478 ++itr;
7485 Unit *Unit::GetOwner() const
7487 if(uint64 ownerid = GetOwnerGUID())
7488 return ObjectAccessor::GetUnit(*this, ownerid);
7489 return NULL;
7492 Unit *Unit::GetCharmer() const
7494 if(uint64 charmerid = GetCharmerGUID())
7495 return ObjectAccessor::GetUnit(*this, charmerid);
7496 return NULL;
7499 Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7501 uint64 guid = GetCharmerOrOwnerGUID();
7502 if(IS_PLAYER_GUID(guid))
7503 return ObjectAccessor::GetPlayer(*this, guid);
7505 return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL;
7508 Pet* Unit::GetPet() const
7510 if(uint64 pet_guid = GetPetGUID())
7512 if(Pet* pet = ObjectAccessor::GetPet(pet_guid))
7513 return pet;
7515 sLog.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid));
7516 const_cast<Unit*>(this)->SetPet(0);
7519 return NULL;
7522 Unit* Unit::GetCharm() const
7524 if(uint64 charm_guid = GetCharmGUID())
7526 if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid))
7527 return pet;
7529 sLog.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid));
7530 const_cast<Unit*>(this)->SetCharm(NULL);
7533 return NULL;
7536 float Unit::GetCombatDistance( const Unit* target ) const
7538 float radius = target->GetFloatValue(UNIT_FIELD_COMBATREACH) + GetFloatValue(UNIT_FIELD_COMBATREACH);
7539 float dx = GetPositionX() - target->GetPositionX();
7540 float dy = GetPositionY() - target->GetPositionY();
7541 float dz = GetPositionZ() - target->GetPositionZ();
7542 float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - radius;
7543 return ( dist > 0 ? dist : 0);
7546 void Unit::SetPet(Pet* pet)
7548 SetUInt64Value(UNIT_FIELD_SUMMON, pet ? pet->GetGUID() : 0);
7550 // FIXME: hack, speed must be set only at follow
7551 if(pet && GetTypeId()==TYPEID_PLAYER)
7552 for(int i = 0; i < MAX_MOVE_TYPE; ++i)
7553 pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
7556 void Unit::SetCharm(Unit* pet)
7558 SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0);
7560 if(GetTypeId() == TYPEID_PLAYER)
7561 ((Player*)this)->m_mover = pet ? pet : this;
7565 void Unit::AddGuardian( Pet* pet )
7567 m_guardianPets.insert(pet->GetGUID());
7571 void Unit::RemoveGuardian( Pet* pet )
7573 m_guardianPets.erase(pet->GetGUID());
7576 void Unit::RemoveGuardians()
7578 while(!m_guardianPets.empty())
7580 uint64 guid = *m_guardianPets.begin();
7581 if(Pet* pet = ObjectAccessor::GetPet(guid))
7582 pet->Remove(PET_SAVE_AS_DELETED);
7584 m_guardianPets.erase(guid);
7588 Pet* Unit::FindGuardianWithEntry(uint32 entry)
7590 // pet guid middle part is entry (and creature also)
7591 // and in guardian list must be guardians with same entry _always_
7592 for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr)
7594 if(Pet* pet = ObjectAccessor::GetPet(*itr))
7595 if (pet->GetEntry() == entry)
7596 return pet;
7599 return NULL;
7602 void Unit::UnsummonAllTotems()
7604 for (int8 i = 0; i < MAX_TOTEM; ++i)
7606 if(!m_TotemSlot[i])
7607 continue;
7609 Creature *OldTotem = GetMap()->GetCreature(m_TotemSlot[i]);
7610 if (OldTotem && OldTotem->isTotem())
7611 ((Totem*)OldTotem)->UnSummon();
7615 int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical)
7617 int32 gain = pVictim->ModifyHealth(int32(addhealth));
7619 if (GetTypeId()==TYPEID_PLAYER)
7621 // overheal = addhealth - gain
7622 SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical);
7624 if (BattleGround *bg = ((Player*)this)->GetBattleGround())
7625 bg->UpdatePlayerScore((Player*)this, SCORE_HEALING_DONE, gain);
7627 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
7628 if (gain)
7629 ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
7631 ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
7634 if (pVictim->GetTypeId()==TYPEID_PLAYER)
7636 ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
7637 ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
7640 return gain;
7643 Unit* Unit::SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo)
7645 if(!victim)
7646 return NULL;
7648 // Magic case
7649 if(spellInfo && (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC))
7651 Unit::AuraList const& magnetAuras = victim->GetAurasByType(SPELL_AURA_SPELL_MAGNET);
7652 for(Unit::AuraList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
7653 if(Unit* magnet = (*itr)->GetCaster())
7654 if(magnet->IsWithinLOSInMap(this) && magnet->isAlive())
7655 return magnet;
7657 // Melee && ranged case
7658 else
7660 AuraList const& hitTriggerAuras = victim->GetAurasByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER);
7661 for(AuraList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
7662 if(Unit* magnet = (*i)->GetCaster())
7663 if(magnet->isAlive() && magnet->IsWithinLOSInMap(this))
7664 if(roll_chance_i((*i)->GetModifier()->m_amount))
7665 return magnet;
7668 return victim;
7671 void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical)
7673 // we guess size
7674 WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1));
7675 data.append(pVictim->GetPackGUID());
7676 data.append(GetPackGUID());
7677 data << uint32(SpellID);
7678 data << uint32(Damage);
7679 data << uint32(OverHeal);
7680 data << uint8(critical ? 1 : 0);
7681 data << uint8(0); // unused in client?
7682 SendMessageToSet(&data, true);
7685 void Unit::SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype)
7687 WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
7688 data.append(pVictim->GetPackGUID());
7689 data.append(GetPackGUID());
7690 data << uint32(SpellID);
7691 data << uint32(powertype);
7692 data << uint32(Damage);
7693 SendMessageToSet(&data, true);
7696 void Unit::EnergizeBySpell(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype)
7698 SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype);
7699 // needs to be called after sending spell log
7700 ModifyPower(powertype, Damage);
7703 uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
7705 if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
7706 return pdamage;
7708 // For totems get damage bonus from owner (statue isn't totem in fact)
7709 if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
7711 if(Unit* owner = GetOwner())
7712 return owner->SpellDamageBonus(pVictim, spellProto, pdamage, damagetype);
7715 // Taken/Done total percent damage auras
7716 float DoneTotalMod = 1.0f;
7717 float TakenTotalMod = 1.0f;
7718 int32 DoneTotal = 0;
7719 int32 TakenTotal = 0;
7721 // ..done
7722 // Pet damage
7723 if( GetTypeId() == TYPEID_UNIT && !((Creature*)this)->isPet() )
7724 DoneTotalMod *= ((Creature*)this)->GetSpellDamageMod(((Creature*)this)->GetCreatureInfo()->rank);
7726 AuraList const& mModDamagePercentDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
7727 for(AuraList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
7729 if( ((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto)) &&
7730 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
7731 // -1 == any item class (not wand then)
7732 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
7733 // 0 == any inventory type (not wand then)
7735 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7739 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7740 // Add flat bonus from spell damage versus
7741 DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
7742 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
7743 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
7744 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
7745 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7747 // done scripted mod (take it from owner)
7748 Unit *owner = GetOwner();
7749 if (!owner) owner = this;
7750 AuraList const& mOverrideClassScript= owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7751 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
7753 if (!(*i)->isAffectedOnSpell(spellProto))
7754 continue;
7755 switch((*i)->GetModifier()->m_miscvalue)
7757 case 4920: // Molten Fury
7758 case 4919:
7759 case 6917: // Death's Embrace
7760 case 6926:
7761 case 6928:
7763 if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
7764 DoneTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
7765 break;
7767 // Soul Siphon
7768 case 4992:
7769 case 4993:
7771 // effect 1 m_amount
7772 int32 maxPercent = (*i)->GetModifier()->m_amount;
7773 // effect 0 m_amount
7774 int32 stepPercent = CalculateSpellDamage((*i)->GetSpellProto(), 0, (*i)->GetSpellProto()->EffectBasePoints[0], this);
7775 // count affliction effects and calc additional damage in percentage
7776 int32 modPercent = 0;
7777 AuraMap const& victimAuras = pVictim->GetAuras();
7778 for (AuraMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
7780 SpellEntry const* m_spell = itr->second->GetSpellProto();
7781 if (m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(m_spell->SpellFamilyFlags & UI64LIT(0x0004071B8044C402)))
7782 continue;
7783 modPercent += stepPercent * itr->second->GetStackAmount();
7784 if (modPercent >= maxPercent)
7786 modPercent = maxPercent;
7787 break;
7790 DoneTotalMod *= (modPercent+100.0f)/100.0f;
7791 break;
7793 case 6916: // Death's Embrace
7794 case 6925:
7795 case 6927:
7796 if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT))
7797 DoneTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
7798 break;
7799 case 5481: // Starfire Bonus
7801 if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, UI64LIT(0x0000000000200002)))
7802 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7803 break;
7805 case 4418: // Increased Shock Damage
7806 case 4554: // Increased Lightning Damage
7807 case 4555: // Improved Moonfire
7808 case 5142: // Increased Lightning Damage
7809 case 5147: // Improved Consecration / Libram of Resurgence
7810 case 5148: // Idol of the Shooting Star
7811 case 6008: // Increased Lightning Damage / Totem of Hex
7813 DoneTotal+=(*i)->GetModifier()->m_amount;
7814 break;
7816 // Tundra Stalker
7817 // Merciless Combat
7818 case 7277:
7820 // Merciless Combat
7821 if ((*i)->GetSpellProto()->SpellIconID == 2656)
7823 if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
7824 DoneTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
7826 else // Tundra Stalker
7828 if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0400000000000000)))
7829 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7830 break;
7832 break;
7834 case 7293: // Rage of Rivendare
7836 if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, UI64LIT(0x0200000000000000)))
7837 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7838 break;
7840 // Twisted Faith
7841 case 7377:
7843 if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, UI64LIT(0x0000000000008000), 0, GetGUID()))
7844 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7845 break;
7847 // Marked for Death
7848 case 7598:
7849 case 7599:
7850 case 7600:
7851 case 7601:
7852 case 7602:
7854 if (pVictim->GetAura(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, UI64LIT(0x0000000000000400)))
7855 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7856 break;
7861 // Custom scripted damage
7862 // Ice Lance
7863 if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellIconID == 186)
7865 if (pVictim->isFrozen())
7866 DoneTotalMod *= 3.0f;
7869 // ..taken
7870 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
7871 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
7872 if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
7873 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7875 // .. taken pct: dummy auras
7876 if (pVictim->GetTypeId() == TYPEID_PLAYER)
7878 //Cheat Death
7879 if (Aura *dummy = pVictim->GetDummyAura(45182))
7881 float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
7882 if (mod < dummy->GetModifier()->m_amount)
7883 mod = dummy->GetModifier()->m_amount;
7884 TakenTotalMod *= (mod+100.0f)/100.0f;
7888 // From caster spells
7889 AuraList const& mOwnerTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
7890 for(AuraList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
7891 if( (*i)->GetCasterGUID() == GetGUID() && (*i)->isAffectedOnSpell(spellProto))
7892 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7894 // Mod damage from spell mechanic
7895 uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
7896 if (mechanicMask)
7898 AuraList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
7899 for(AuraList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
7900 if(mechanicMask & uint32(1<<((*i)->GetModifier()->m_miscvalue)))
7901 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
7904 // Taken/Done fixed damage bonus auras
7905 int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto));
7906 int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
7908 // Pets just add their bonus damage to their spell damage
7909 // note that their spell damage is just gain of their own auras
7910 if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
7911 DoneAdvertisedBenefit += ((Pet*)this)->GetBonusDamage();
7913 float LvlPenalty = CalculateLevelPenalty(spellProto);
7914 // Spellmod SpellDamage
7915 float SpellModSpellDamage = 100.0f;
7916 if(Player* modOwner = GetSpellModOwner())
7917 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_SPELL_BONUS_DAMAGE,SpellModSpellDamage);
7918 SpellModSpellDamage /= 100.0f;
7920 // Check for table values
7921 SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
7922 if (bonus)
7924 float coeff;
7925 if (damagetype == DOT)
7926 coeff = bonus->dot_damage * LvlPenalty * stack;
7927 else
7928 coeff = bonus->direct_damage * LvlPenalty * stack;
7930 if (bonus->ap_bonus)
7931 DoneTotal += int32(bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack);
7933 DoneTotal += int32(DoneAdvertisedBenefit * coeff * SpellModSpellDamage);
7934 TakenTotal += int32(TakenAdvertisedBenefit * coeff);
7936 // Default calculation
7937 else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
7939 // Damage Done from spell damage bonus
7940 uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
7941 // Damage over Time spells bonus calculation
7942 float DotFactor = 1.0f;
7943 if(damagetype == DOT)
7945 int32 DotDuration = GetSpellDuration(spellProto);
7946 // 200% limit
7947 if(DotDuration > 0)
7949 if(DotDuration > 30000) DotDuration = 30000;
7950 if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
7951 int x = 0;
7952 for(int j = 0; j < 3; j++)
7954 if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
7955 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
7956 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
7958 x = j;
7959 break;
7962 int32 DotTicks = 6;
7963 if(spellProto->EffectAmplitude[x] != 0)
7964 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
7965 if(DotTicks)
7967 DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks;
7968 TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks;
7972 // Distribute Damage over multiple effects, reduce by AoE
7973 CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
7974 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7975 for(int j = 0; j < 3; ++j)
7977 if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
7978 spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
7980 CastingTime /= 2;
7981 break;
7984 DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage);
7985 TakenTotal+= int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty);
7988 float tmpDamage = (pdamage + DoneTotal) * DoneTotalMod;
7989 // apply spellmod to Done damage (flat and pct)
7990 if(Player* modOwner = GetSpellModOwner())
7991 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
7993 tmpDamage = (tmpDamage + TakenTotal) * TakenTotalMod;
7995 return tmpDamage > 0 ? uint32(tmpDamage) : 0;
7998 int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
8000 int32 DoneAdvertisedBenefit = 0;
8002 // ..done
8003 AuraList const& mDamageDone = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE);
8004 for(AuraList::const_iterator i = mDamageDone.begin();i != mDamageDone.end(); ++i)
8005 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0 &&
8006 (*i)->GetSpellProto()->EquippedItemClass == -1 &&
8007 // -1 == any item class (not wand then)
8008 (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
8009 // 0 == any inventory type (not wand then)
8010 DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
8012 if (GetTypeId() == TYPEID_PLAYER)
8014 // Base value
8015 DoneAdvertisedBenefit +=((Player*)this)->GetBaseSpellDamageBonus();
8017 // Damage bonus from stats
8018 AuraList const& mDamageDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
8019 for(AuraList::const_iterator i = mDamageDoneOfStatPercent.begin();i != mDamageDoneOfStatPercent.end(); ++i)
8021 if((*i)->GetModifier()->m_miscvalue & schoolMask)
8023 // stat used stored in miscValueB for this aura
8024 Stats usedStat = Stats((*i)->GetMiscBValue());
8025 DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
8028 // ... and attack power
8029 AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
8030 for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
8031 if ((*i)->GetModifier()->m_miscvalue & schoolMask)
8032 DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
8035 return DoneAdvertisedBenefit;
8038 int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim)
8040 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8042 int32 TakenAdvertisedBenefit = 0;
8043 // ..done (for creature type by mask) in taken
8044 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
8045 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
8046 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8047 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
8049 // ..taken
8050 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
8051 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
8052 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
8053 TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
8055 return TakenAdvertisedBenefit;
8058 bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType)
8060 // not critting spell
8061 if((spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_CRIT))
8062 return false;
8064 float crit_chance = 0.0f;
8065 switch(spellProto->DmgClass)
8067 case SPELL_DAMAGE_CLASS_NONE:
8068 return false;
8069 case SPELL_DAMAGE_CLASS_MAGIC:
8071 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
8072 crit_chance = 0.0f;
8073 // For other schools
8074 else if (GetTypeId() == TYPEID_PLAYER)
8075 crit_chance = GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask));
8076 else
8078 crit_chance = m_baseSpellCritChance;
8079 crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
8081 // taken
8082 if (pVictim)
8084 if (!IsPositiveSpell(spellProto->Id))
8086 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
8087 crit_chance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
8088 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
8089 crit_chance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
8090 // Modify by player victim resilience
8091 if (pVictim->GetTypeId() == TYPEID_PLAYER)
8092 crit_chance -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL);
8095 // scripted (increase crit chance ... against ... target by x%
8096 AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8097 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
8099 if (!((*i)->isAffectedOnSpell(spellProto)))
8100 continue;
8101 switch((*i)->GetModifier()->m_miscvalue)
8103 case 849: if (pVictim->isFrozen()) crit_chance+= 17.0f; break; //Shatter Rank 1
8104 case 910: if (pVictim->isFrozen()) crit_chance+= 34.0f; break; //Shatter Rank 2
8105 case 911: if (pVictim->isFrozen()) crit_chance+= 50.0f; break; //Shatter Rank 3
8106 case 7917: // Glyph of Shadowburn
8107 if (pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
8108 crit_chance+=(*i)->GetModifier()->m_amount;
8109 break;
8110 case 7997: // Renewed Hope
8111 case 7998:
8112 if (pVictim->HasAura(6788))
8113 crit_chance+=(*i)->GetModifier()->m_amount;
8114 break;
8115 case 21: // Test of Faith
8116 case 6935:
8117 case 6918:
8118 if (pVictim->GetHealth() < pVictim->GetMaxHealth()/2)
8119 crit_chance+=(*i)->GetModifier()->m_amount;
8120 break;
8121 default:
8122 break;
8125 // Custom crit by class
8126 switch(spellProto->SpellFamilyName)
8128 case SPELLFAMILY_PALADIN:
8129 // Sacred Shield
8130 if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000040000000))
8132 Aura *aura = pVictim->GetDummyAura(58597);
8133 if (aura && aura->GetCasterGUID() == GetGUID())
8134 crit_chance+=aura->GetModifier()->m_amount;
8135 break;
8137 break;
8138 case SPELLFAMILY_SHAMAN:
8139 // Lava Burst
8140 if (spellProto->SpellFamilyFlags & UI64LIT(0x0000100000000000))
8142 if (Aura *flameShock = pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, UI64LIT(0x0000000010000000), 0, GetGUID()))
8144 // Consume shock aura if not have Glyph of Flame Shock
8145 if (!GetAura(55447, 0))
8146 pVictim->RemoveAurasByCasterSpell(flameShock->GetId(), GetGUID());
8147 return true;
8149 break;
8151 break;
8155 break;
8157 case SPELL_DAMAGE_CLASS_MELEE:
8158 case SPELL_DAMAGE_CLASS_RANGED:
8160 if (pVictim)
8162 crit_chance = GetUnitCriticalChance(attackType, pVictim);
8163 crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
8165 break;
8167 default:
8168 return false;
8170 // percent done
8171 // only players use intelligence for critical chance computations
8172 if(Player* modOwner = GetSpellModOwner())
8173 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
8175 crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f;
8176 if (roll_chance_f(crit_chance))
8177 return true;
8178 return false;
8181 uint32 Unit::SpellCriticalDamageBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
8183 // Calculate critical bonus
8184 int32 crit_bonus;
8185 switch(spellProto->DmgClass)
8187 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
8188 case SPELL_DAMAGE_CLASS_RANGED:
8189 // TODO: write here full calculation for melee/ranged spells
8190 crit_bonus = damage;
8191 break;
8192 default:
8193 crit_bonus = damage / 2; // for spells is 50%
8194 break;
8197 // adds additional damage to crit_bonus (from talents)
8198 if(Player* modOwner = GetSpellModOwner())
8199 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
8201 if(pVictim)
8203 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8204 crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
8207 if(crit_bonus > 0)
8208 damage += crit_bonus;
8210 return damage;
8213 uint32 Unit::SpellCriticalHealingBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim)
8215 // Calculate critical bonus
8216 int32 crit_bonus;
8217 switch(spellProto->DmgClass)
8219 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
8220 case SPELL_DAMAGE_CLASS_RANGED:
8221 // TODO: write here full calculation for melee/ranged spells
8222 crit_bonus = damage;
8223 break;
8224 default:
8225 crit_bonus = damage / 2; // for spells is 50%
8226 break;
8229 if(pVictim)
8231 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8232 crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
8235 if(crit_bonus > 0)
8236 damage += crit_bonus;
8238 damage = int32(damage * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
8240 return damage;
8243 uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack)
8245 // No heal amount for this class spells
8246 if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
8247 return healamount;
8249 // For totems get healing bonus from owner (statue isn't totem in fact)
8250 if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem() && ((Totem*)this)->GetTotemType()!=TOTEM_STATUE)
8251 if(Unit* owner = GetOwner())
8252 return owner->SpellHealingBonus(pVictim, spellProto, healamount, damagetype, stack);
8254 // Healing Done
8255 // Taken/Done total percent damage auras
8256 float DoneTotalMod = 1.0f;
8257 float TakenTotalMod = 1.0f;
8258 int32 DoneTotal = 0;
8259 int32 TakenTotal = 0;
8261 // Healing done percent
8262 AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
8263 for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
8264 DoneTotalMod *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
8266 // done scripted mod (take it from owner)
8267 Unit *owner = GetOwner();
8268 if (!owner) owner = this;
8269 AuraList const& mOverrideClassScript= owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8270 for(AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
8272 if (!(*i)->isAffectedOnSpell(spellProto))
8273 continue;
8274 switch((*i)->GetModifier()->m_miscvalue)
8276 case 4415: // Increased Rejuvenation Healing
8277 case 4953:
8278 case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
8279 DoneTotal+=(*i)->GetModifier()->m_amount;
8280 break;
8281 case 7997: // Renewed Hope
8282 case 7998:
8283 if (pVictim->HasAura(6788))
8284 DoneTotalMod *=((*i)->GetModifier()->m_amount + 100.0f)/100.0f;
8285 break;
8286 case 21: // Test of Faith
8287 case 6935:
8288 case 6918:
8289 if (pVictim->GetHealth() < pVictim->GetMaxHealth()/2)
8290 DoneTotalMod *=((*i)->GetModifier()->m_amount + 100.0f)/100.0f;
8291 break;
8292 case 7798: // Glyph of Regrowth
8294 if (pVictim->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, UI64LIT(0x0000000000000040)))
8295 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8296 break;
8298 case 8477: // Nourish Heal Boost
8300 int32 stepPercent = (*i)->GetModifier()->m_amount;
8301 int32 modPercent = 0;
8302 AuraMap const& victimAuras = pVictim->GetAuras();
8303 for (AuraMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
8305 if (itr->second->GetCasterGUID()!=GetGUID())
8306 continue;
8307 SpellEntry const* m_spell = itr->second->GetSpellProto();
8308 if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
8309 !(m_spell->SpellFamilyFlags & UI64LIT(0x0000001000000050)))
8310 continue;
8311 modPercent += stepPercent * itr->second->GetStackAmount();
8313 DoneTotalMod *= (modPercent+100.0f)/100.0f;
8314 break;
8316 case 7871: // Glyph of Lesser Healing Wave
8318 if (pVictim->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, UI64LIT(0x0000040000000000), 0, GetGUID()))
8319 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8320 break;
8322 default:
8323 break;
8327 // Taken/Done fixed damage bonus auras
8328 int32 DoneAdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
8329 int32 TakenAdvertisedBenefit = SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), pVictim);
8331 float LvlPenalty = CalculateLevelPenalty(spellProto);
8332 // Spellmod SpellDamage
8333 float SpellModSpellDamage = 100.0f;
8334 if(Player* modOwner = GetSpellModOwner())
8335 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_SPELL_BONUS_DAMAGE, SpellModSpellDamage);
8336 SpellModSpellDamage /= 100.0f;
8338 // Check for table values
8339 SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
8340 if (bonus)
8342 float coeff;
8343 if (damagetype == DOT)
8344 coeff = bonus->dot_damage * LvlPenalty * stack;
8345 else
8346 coeff = bonus->direct_damage * LvlPenalty * stack;
8348 if (bonus->ap_bonus)
8349 DoneTotal += int32(bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack);
8351 DoneTotal += int32(DoneAdvertisedBenefit * coeff * SpellModSpellDamage);
8352 TakenTotal += int32(TakenAdvertisedBenefit * coeff);
8354 // Default calculation
8355 else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
8357 // Damage Done from spell damage bonus
8358 uint32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
8359 // Damage over Time spells bonus calculation
8360 float DotFactor = 1.0f;
8361 if(damagetype == DOT)
8363 int32 DotDuration = GetSpellDuration(spellProto);
8364 // 200% limit
8365 if(DotDuration > 0)
8367 if(DotDuration > 30000) DotDuration = 30000;
8368 if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
8369 int x = 0;
8370 for(int j = 0; j < 3; j++)
8372 if( spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
8373 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
8374 spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH) )
8376 x = j;
8377 break;
8380 int32 DotTicks = 6;
8381 if(spellProto->EffectAmplitude[x] != 0)
8382 DotTicks = DotDuration / spellProto->EffectAmplitude[x];
8383 if(DotTicks)
8385 DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks;
8386 TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks;
8390 // Distribute Damage over multiple effects, reduce by AoE
8391 CastingTime = GetCastingTimeForBonus( spellProto, damagetype, CastingTime );
8392 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
8393 for(int j = 0; j < 3; ++j)
8395 if( spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
8396 spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH )
8398 CastingTime /= 2;
8399 break;
8402 DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f);
8403 TakenTotal += int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * 1.88f);
8406 // use float as more appropriate for negative values and percent applying
8407 float heal = (healamount + DoneTotal)*DoneTotalMod;
8408 // apply spellmod to Done amount
8409 if(Player* modOwner = GetSpellModOwner())
8410 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
8412 // Taken mods
8413 // Healing Wave cast
8414 if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000040)))
8416 // Search for Healing Way on Victim
8417 Unit::AuraList const& auraDummy = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
8418 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr!=auraDummy.end(); ++itr)
8419 if((*itr)->GetId() == 29203)
8420 TakenTotalMod *= ((*itr)->GetModifier()->m_amount+100.0f) / 100.0f;
8423 // Healing taken percent
8424 float minval = pVictim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
8425 if(minval)
8426 TakenTotalMod *= (100.0f + minval) / 100.0f;
8428 float maxval = pVictim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
8429 if(maxval)
8430 TakenTotalMod *= (100.0f + maxval) / 100.0f;
8432 AuraList const& mHealingGet= pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING_RECEIVED);
8433 for(AuraList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
8434 if ((*i)->isAffectedOnSpell(spellProto))
8435 TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f;
8437 heal = (heal + TakenTotal) * TakenTotalMod;
8439 return heal < 0 ? 0 : uint32(heal);
8442 int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
8444 int32 AdvertisedBenefit = 0;
8446 AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
8447 for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
8448 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
8449 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
8451 // Healing bonus of spirit, intellect and strength
8452 if (GetTypeId() == TYPEID_PLAYER)
8454 // Base value
8455 AdvertisedBenefit +=((Player*)this)->GetBaseSpellHealingBonus();
8457 // Healing bonus from stats
8458 AuraList const& mHealingDoneOfStatPercent = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
8459 for(AuraList::const_iterator i = mHealingDoneOfStatPercent.begin();i != mHealingDoneOfStatPercent.end(); ++i)
8461 // stat used dependent from misc value (stat index)
8462 Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
8463 AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
8466 // ... and attack power
8467 AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
8468 for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
8469 if ((*i)->GetModifier()->m_miscvalue & schoolMask)
8470 AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
8472 return AdvertisedBenefit;
8475 int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim)
8477 int32 AdvertisedBenefit = 0;
8478 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
8479 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
8480 if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
8481 AdvertisedBenefit += (*i)->GetModifier()->m_amount;
8482 return AdvertisedBenefit;
8485 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask)
8487 //If m_immuneToSchool type contain this school type, IMMUNE damage.
8488 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
8489 for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
8490 if(itr->type & shoolMask)
8491 return true;
8493 //If m_immuneToDamage type contain magic, IMMUNE damage.
8494 SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
8495 for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
8496 if(itr->type & shoolMask)
8497 return true;
8499 return false;
8502 bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo)
8504 if (!spellInfo)
8505 return false;
8507 //TODO add spellEffect immunity checks!, player with flag in bg is imune to imunity buffs from other friendly players!
8508 //SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_EFFECT];
8510 SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
8511 for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
8512 if(itr->type == spellInfo->Dispel)
8513 return true;
8515 if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && // unaffected by school immunity
8516 !(spellInfo->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)) // can remove immune (by dispell or immune it)
8518 SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
8519 for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
8520 if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) &&
8521 (itr->type & GetSpellSchoolMask(spellInfo)) )
8522 return true;
8525 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
8526 for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
8528 if(itr->type == spellInfo->Mechanic)
8530 return true;
8534 return false;
8537 bool Unit::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
8539 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8540 uint32 effect = spellInfo->Effect[index];
8541 SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
8542 for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
8543 if(itr->type == effect)
8544 return true;
8546 if(uint32 mechanic = spellInfo->EffectMechanic[index])
8548 SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
8549 for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
8550 if(itr->type == mechanic)
8551 return true;
8554 if(uint32 aura = spellInfo->EffectApplyAuraName[index])
8556 SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
8557 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
8558 if(itr->type == aura)
8559 return true;
8560 // Check for immune to application of harmful magical effects
8561 AuraList const& immuneAuraApply = GetAurasByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
8562 for(AuraList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
8563 if (spellInfo->Dispel == DISPEL_MAGIC && // Magic debuff
8564 ((*iter)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellInfo)) && // Check school
8565 !IsPositiveEffect(spellInfo->Id, index)) // Harmful
8566 return true;
8569 return false;
8572 bool Unit::IsDamageToThreatSpell(SpellEntry const * spellInfo) const
8574 if(!spellInfo)
8575 return false;
8577 uint32 family = spellInfo->SpellFamilyName;
8578 uint64 flags = spellInfo->SpellFamilyFlags;
8580 if((family == 5 && flags == 256) || //Searing Pain
8581 (family == 6 && flags == 8192) || //Mind Blast
8582 (family == 11 && flags == 1048576)) //Earth Shock
8583 return true;
8585 return false;
8588 void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attType, SpellEntry const *spellProto)
8590 if(!pVictim)
8591 return;
8593 if(*pdamage == 0)
8594 return;
8596 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8598 // Taken/Done fixed damage bonus auras
8599 int32 DoneFlatBenefit = 0;
8600 int32 TakenFlatBenefit = 0;
8602 // ..done (for creature type by mask) in taken
8603 AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
8604 for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
8605 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8606 DoneFlatBenefit += (*i)->GetModifier()->m_amount;
8608 // ..done
8609 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8611 // ..done (base at attack power for marked target and base at attack power for creature type)
8612 int32 APbonus = 0;
8613 if(attType == RANGED_ATTACK)
8615 APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
8617 // ..done (base at attack power and creature type)
8618 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
8619 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
8620 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8621 APbonus += (*i)->GetModifier()->m_amount;
8623 else
8625 APbonus += pVictim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
8627 // ..done (base at attack power and creature type)
8628 AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
8629 for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
8630 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8631 APbonus += (*i)->GetModifier()->m_amount;
8634 if (APbonus!=0) // Can be negative
8636 bool normalized = false;
8637 if(spellProto)
8639 for (uint8 i = 0; i<3;++i)
8641 if (spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
8643 normalized = true;
8644 break;
8649 DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized));
8652 // ..taken
8653 AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
8654 for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
8655 if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
8656 TakenFlatBenefit += (*i)->GetModifier()->m_amount;
8658 if(attType!=RANGED_ATTACK)
8659 TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
8660 else
8661 TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
8663 // Done/Taken total percent damage auras
8664 float DoneTotalMod = 1.0f;
8665 float TakenTotalMod = 1.0f;
8667 // ..done
8668 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8669 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8671 AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
8672 for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
8673 if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
8674 DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8676 // ..taken
8677 AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
8678 for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
8679 if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
8680 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8682 // .. taken pct: dummy auras
8683 AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
8684 for(AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
8686 switch((*i)->GetSpellProto()->SpellIconID)
8688 //Cheat Death
8689 case 2109:
8690 if((*i)->GetModifier()->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
8692 if(pVictim->GetTypeId() != TYPEID_PLAYER)
8693 continue;
8694 float mod = ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE)*(-8.0f);
8695 if (mod < (*i)->GetModifier()->m_amount)
8696 mod = (*i)->GetModifier()->m_amount;
8697 TakenTotalMod *= (mod+100.0f)/100.0f;
8699 break;
8700 //Mangle
8701 case 2312:
8702 if(spellProto==NULL)
8703 break;
8704 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8705 if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags == UI64LIT(0x00008000)))
8706 TakenTotalMod *= (100.0f+(*i)->GetModifier()->m_amount)/100.0f;
8707 break;
8711 // .. taken pct: class scripts
8712 AuraList const& mclassScritAuras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8713 for(AuraList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
8715 switch((*i)->GetMiscValue())
8717 case 6427: case 6428: // Dirty Deeds
8718 if(pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
8720 Aura* eff0 = GetAura((*i)->GetId(),0);
8721 if(!eff0 || (*i)->GetEffIndex()!=1)
8723 sLog.outError("Spell structure of DD (%u) changed.",(*i)->GetId());
8724 continue;
8727 // effect 0 have expected value but in negative state
8728 TakenTotalMod *= (-eff0->GetModifier()->m_amount+100.0f)/100.0f;
8730 break;
8734 if(attType != RANGED_ATTACK)
8736 AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
8737 for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
8738 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8740 else
8742 AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
8743 for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
8744 TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
8747 float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
8749 // apply spellmod to Done damage
8750 if(spellProto)
8752 if(Player* modOwner = GetSpellModOwner())
8753 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
8756 tmpDamage = (tmpDamage + TakenFlatBenefit)*TakenTotalMod;
8758 // bonus result can be negative
8759 *pdamage = tmpDamage > 0 ? uint32(tmpDamage) : 0;
8762 void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
8764 if (apply)
8766 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
8768 next = itr; ++next;
8769 if(itr->type == type)
8771 m_spellImmune[op].erase(itr);
8772 next = m_spellImmune[op].begin();
8775 SpellImmune Immune;
8776 Immune.spellId = spellId;
8777 Immune.type = type;
8778 m_spellImmune[op].push_back(Immune);
8780 else
8782 for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
8784 if(itr->spellId == spellId)
8786 m_spellImmune[op].erase(itr);
8787 break;
8794 void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply)
8796 ApplySpellImmune(spellProto->Id,IMMUNITY_DISPEL, type, apply);
8798 if (apply && spellProto->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
8799 RemoveAurasWithDispelType(type);
8802 float Unit::GetWeaponProcChance() const
8804 // normalized proc chance for weapon attack speed
8805 // (odd formula...)
8806 if(isAttackReady(BASE_ATTACK))
8807 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8808 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
8809 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8810 return 0;
8813 float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM) const
8815 // proc per minute chance calculation
8816 if (PPM <= 0) return 0.0f;
8817 uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8818 return result;
8821 void Unit::Mount(uint32 mount)
8823 if(!mount)
8824 return;
8826 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING);
8828 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
8830 SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
8832 // unsummon pet
8833 if(GetTypeId() == TYPEID_PLAYER)
8834 ((Player*)this)->UnsummonPetTemporaryIfAny();
8837 void Unit::Unmount()
8839 if(!IsMounted())
8840 return;
8842 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED);
8844 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
8845 RemoveFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT );
8847 // only resummon old pet if the player is already added to a map
8848 // this prevents adding a pet to a not created map which would otherwise cause a crash
8849 // (it could probably happen when logging in after a previous crash)
8850 if(GetTypeId() == TYPEID_PLAYER)
8851 ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny();
8854 void Unit::SetInCombatWith(Unit* enemy)
8856 Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf();
8857 if(eOwner->IsPvP())
8859 SetInCombatState(true,enemy);
8860 return;
8863 //check for duel
8864 if(eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel)
8866 Unit const* myOwner = GetCharmerOrOwnerOrSelf();
8867 if(((Player const*)eOwner)->duel->opponent == myOwner)
8869 SetInCombatState(true,enemy);
8870 return;
8873 SetInCombatState(false,enemy);
8876 void Unit::SetInCombatState(bool PvP, Unit* enemy)
8878 // only alive units can be in combat
8879 if(!isAlive())
8880 return;
8882 if(PvP)
8883 m_CombatTimer = 5000;
8885 bool creatureNotInCombat = GetTypeId()==TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
8887 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
8889 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
8890 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
8892 if(creatureNotInCombat && ((Creature*)this)->AI())
8893 ((Creature*)this)->AI()->EnterCombat(enemy);
8896 void Unit::ClearInCombat()
8898 m_CombatTimer = 0;
8899 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
8901 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
8902 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
8904 // Player's state will be cleared in Player::UpdateContestedPvP
8905 if(GetTypeId()!=TYPEID_PLAYER)
8906 clearUnitState(UNIT_STAT_ATTACK_PLAYER);
8907 else
8908 ((Player*)this)->UpdatePotionCooldown();
8911 bool Unit::isTargetableForAttack() const
8913 if (GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
8914 return false;
8916 if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
8917 return false;
8919 return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/;
8922 int32 Unit::ModifyHealth(int32 dVal)
8924 int32 gain = 0;
8926 if(dVal==0)
8927 return 0;
8929 int32 curHealth = (int32)GetHealth();
8931 int32 val = dVal + curHealth;
8932 if(val <= 0)
8934 SetHealth(0);
8935 return -curHealth;
8938 int32 maxHealth = (int32)GetMaxHealth();
8940 if(val < maxHealth)
8942 SetHealth(val);
8943 gain = val - curHealth;
8945 else if(curHealth != maxHealth)
8947 SetHealth(maxHealth);
8948 gain = maxHealth - curHealth;
8951 return gain;
8954 int32 Unit::ModifyPower(Powers power, int32 dVal)
8956 int32 gain = 0;
8958 if(dVal==0)
8959 return 0;
8961 int32 curPower = (int32)GetPower(power);
8963 int32 val = dVal + curPower;
8964 if(val <= 0)
8966 SetPower(power,0);
8967 return -curPower;
8970 int32 maxPower = (int32)GetMaxPower(power);
8972 if(val < maxPower)
8974 SetPower(power,val);
8975 gain = val - curPower;
8977 else if(curPower != maxPower)
8979 SetPower(power,maxPower);
8980 gain = maxPower - curPower;
8983 return gain;
8986 bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const
8988 if(!u)
8989 return false;
8991 // Always can see self
8992 if (u==this)
8993 return true;
8995 // player visible for other player if not logout and at same transport
8996 // including case when player is out of world
8997 bool at_same_transport =
8998 GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER &&
8999 !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() &&
9000 !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() &&
9001 ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport();
9003 // not in world
9004 if(!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
9005 return false;
9007 // forbidden to seen (at GM respawn command)
9008 if(m_Visibility==VISIBILITY_RESPAWN)
9009 return false;
9011 // Grid dead/alive checks
9012 if( u->GetTypeId()==TYPEID_PLAYER)
9014 // non visible at grid for any stealth state
9015 if(!IsVisibleInGridForPlayer((Player *)u))
9016 return false;
9018 // if player is dead then he can't detect anyone in any cases
9019 if(!u->isAlive())
9020 detect = false;
9022 else
9024 // all dead creatures/players not visible for any creatures
9025 if(!u->isAlive() || !isAlive())
9026 return false;
9029 // always seen by owner
9030 if(GetCharmerOrOwnerGUID()==u->GetGUID())
9031 return true;
9033 // different visible distance checks
9034 if(u->isInFlight()) // what see player in flight
9036 // use object grey distance for all (only see objects any way)
9037 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
9038 return false;
9040 else if(!isAlive()) // distance for show body
9042 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
9043 return false;
9045 else if(GetTypeId()==TYPEID_PLAYER) // distance for show player
9047 if(u->GetTypeId()==TYPEID_PLAYER)
9049 // Players far than max visible distance for player or not in our map are not visible too
9050 if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
9051 return false;
9053 else
9055 // Units far than max visible distance for creature or not in our map are not visible too
9056 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
9057 return false;
9060 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
9062 // Pet/charmed far than max visible distance for player or not in our map are not visible too
9063 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
9064 return false;
9066 else // distance for show creature
9068 // Units far than max visible distance for creature or not in our map are not visible too
9069 if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
9070 return false;
9073 // Visible units, always are visible for all units, except for units under invisibility and phases
9074 if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0 && InSamePhase(u))
9075 return true;
9077 // GMs see any players, not higher GMs and all units in any phase
9078 if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster())
9080 if(GetTypeId() == TYPEID_PLAYER)
9081 return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity();
9082 else
9083 return true;
9086 // non faction visibility non-breakable for non-GMs
9087 if (m_Visibility == VISIBILITY_OFF)
9088 return false;
9090 // phased visibility (both must phased in same way)
9091 if(!InSamePhase(u))
9092 return false;
9094 // raw invisibility
9095 bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0);
9097 // detectable invisibility case
9098 if( invisible && (
9099 // Invisible units, always are visible for units under same invisibility type
9100 (m_invisibilityMask & u->m_invisibilityMask)!=0 ||
9101 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
9102 u->canDetectInvisibilityOf(this) ||
9103 // Units that can detect invisibility always are visible for units that can be detected
9104 canDetectInvisibilityOf(u) ))
9106 invisible = false;
9109 // special cases for always overwrite invisibility/stealth
9110 if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH)
9112 // non-hostile case
9113 if (!u->IsHostileTo(this))
9115 // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
9116 if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER)
9118 if(((Player*)this)->IsGroupVisibleFor(((Player*)u)))
9119 return true;
9121 // else apply same rules as for hostile case (detecting check for stealth)
9124 // hostile case
9125 else
9127 // Hunter mark functionality
9128 AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED);
9129 for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
9130 if((*iter)->GetCasterGUID()==u->GetGUID())
9131 return true;
9133 // else apply detecting check for stealth
9136 // none other cases for detect invisibility, so invisible
9137 if(invisible)
9138 return false;
9140 // else apply stealth detecting check
9143 // unit got in stealth in this moment and must ignore old detected state
9144 if (m_Visibility == VISIBILITY_GROUP_NO_DETECT)
9145 return false;
9147 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
9148 if (m_Visibility != VISIBILITY_GROUP_STEALTH)
9149 return true;
9151 // NOW ONLY STEALTH CASE
9153 // stealth and detected and visible for some seconds
9154 if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this))
9155 return true;
9157 //if in non-detect mode then invisible for unit
9158 if (!detect)
9159 return false;
9161 // Special cases
9163 // If is attacked then stealth is lost, some creature can use stealth too
9164 if( !getAttackers().empty() )
9165 return true;
9167 // If there is collision rogue is seen regardless of level difference
9168 if (IsWithinDist(u,0.24f))
9169 return true;
9171 //If a mob or player is stunned he will not be able to detect stealth
9172 if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this))
9173 return false;
9175 // Creature can detect target only in aggro radius
9176 if(u->GetTypeId() != TYPEID_PLAYER)
9178 //Always invisible from back and out of aggro range
9179 bool isInFront = u->isInFrontInMap(this,((Creature const*)u)->GetAttackDistance(this));
9180 if(!isInFront)
9181 return false;
9183 else
9185 //Always invisible from back
9186 bool isInFront = u->isInFrontInMap(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
9187 if(!isInFront)
9188 return false;
9191 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
9192 if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH))
9194 //Calculation if target is in front
9196 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
9197 float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f);
9199 //Visible distance is modified by
9200 //-Level Diff (every level diff = 1.0f in visible distance)
9201 visibleDistance += int32(u->getLevelForTarget(this)) - int32(getLevelForTarget(u));
9203 //This allows to check talent tree and will add addition stealth dependent on used points)
9204 int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL);
9205 if(stealthMod < 0)
9206 stealthMod = 0;
9208 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
9209 //based on wowwiki every 5 mod we have 1 more level diff in calculation
9210 visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f;
9212 if(!IsWithinDist(u,visibleDistance))
9213 return false;
9216 // Now check is target visible with LoS
9217 float ox,oy,oz;
9218 u->GetPosition(ox,oy,oz);
9219 return IsWithinLOS(ox,oy,oz);
9222 void Unit::SetVisibility(UnitVisibility x)
9224 m_Visibility = x;
9226 if(IsInWorld())
9228 Map *m = GetMap();
9230 if(GetTypeId()==TYPEID_PLAYER)
9231 m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
9232 else
9233 m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
9237 bool Unit::canDetectInvisibilityOf(Unit const* u) const
9239 if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask))
9241 for(uint32 i = 0; i < 10; ++i)
9243 if(((1 << i) & mask)==0)
9244 continue;
9246 // find invisibility level
9247 uint32 invLevel = 0;
9248 Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
9249 for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
9250 if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount)
9251 invLevel = (*itr)->GetModifier()->m_amount;
9253 // find invisibility detect level
9254 uint32 detectLevel = 0;
9255 Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
9256 for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr)
9257 if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount)
9258 detectLevel = (*itr)->GetModifier()->m_amount;
9260 if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case
9262 detectLevel = ((Player*)this)->GetDrunkValue();
9265 if(invLevel <= detectLevel)
9266 return true;
9270 return false;
9273 void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
9275 int32 main_speed_mod = 0;
9276 float stack_bonus = 1.0f;
9277 float non_stack_bonus = 1.0f;
9279 switch(mtype)
9281 case MOVE_WALK:
9282 return;
9283 case MOVE_RUN:
9285 if (IsMounted()) // Use on mount auras
9287 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED);
9288 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS);
9289 non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK))/100.0f;
9291 else
9293 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED);
9294 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS);
9295 non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK))/100.0f;
9297 break;
9299 case MOVE_RUN_BACK:
9300 return;
9301 case MOVE_SWIM:
9303 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED);
9304 break;
9306 case MOVE_SWIM_BACK:
9307 return;
9308 case MOVE_FLIGHT:
9310 if (IsMounted()) // Use on mount auras
9311 main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED);
9312 else // Use not mount (shapeshift for example) auras (should stack)
9313 main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT);
9314 stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS);
9315 non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f;
9316 break;
9318 case MOVE_FLIGHT_BACK:
9319 return;
9320 default:
9321 sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype);
9322 return;
9325 float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus;
9326 // now we ready for speed calculation
9327 float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus;
9329 switch(mtype)
9331 case MOVE_RUN:
9332 case MOVE_SWIM:
9333 case MOVE_FLIGHT:
9335 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
9336 // TODO: possible affect only on MOVE_RUN
9337 if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
9339 // Use speed from aura
9340 float max_speed = normalization / baseMoveSpeed[mtype];
9341 if (speed > max_speed)
9342 speed = max_speed;
9344 break;
9346 default:
9347 break;
9350 // Apply strongest slow aura mod to speed
9351 int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED);
9352 if (slow)
9353 speed *=(100.0f + slow)/100.0f;
9354 SetSpeed(mtype, speed, forced);
9357 float Unit::GetSpeed( UnitMoveType mtype ) const
9359 return m_speed_rate[mtype]*baseMoveSpeed[mtype];
9362 void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
9364 if (rate < 0)
9365 rate = 0.0f;
9367 // Update speed only on change
9368 if (m_speed_rate[mtype] == rate)
9369 return;
9371 m_speed_rate[mtype] = rate;
9373 propagateSpeedChange();
9375 WorldPacket data;
9376 if(!forced)
9378 switch(mtype)
9380 case MOVE_WALK:
9381 data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+2+4+4+4+4+4+4+4);
9382 break;
9383 case MOVE_RUN:
9384 data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+2+4+4+4+4+4+4+4);
9385 break;
9386 case MOVE_RUN_BACK:
9387 data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
9388 break;
9389 case MOVE_SWIM:
9390 data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+2+4+4+4+4+4+4+4);
9391 break;
9392 case MOVE_SWIM_BACK:
9393 data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
9394 break;
9395 case MOVE_TURN_RATE:
9396 data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+2+4+4+4+4+4+4+4);
9397 break;
9398 case MOVE_FLIGHT:
9399 data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+2+4+4+4+4+4+4+4);
9400 break;
9401 case MOVE_FLIGHT_BACK:
9402 data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4);
9403 break;
9404 case MOVE_PITCH_RATE:
9405 data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8+4+2+4+4+4+4+4+4+4);
9406 break;
9407 default:
9408 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
9409 return;
9412 data.append(GetPackGUID());
9413 data << uint32(0); // movement flags
9414 data << uint16(0); // unk flags
9415 data << uint32(getMSTime());
9416 data << float(GetPositionX());
9417 data << float(GetPositionY());
9418 data << float(GetPositionZ());
9419 data << float(GetOrientation());
9420 data << uint32(0); // fall time
9421 data << float(GetSpeed(mtype));
9422 SendMessageToSet( &data, true );
9424 else
9426 if(GetTypeId() == TYPEID_PLAYER)
9428 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
9429 // and do it only for real sent packets and use run for run/mounted as client expected
9430 ++((Player*)this)->m_forced_speed_changes[mtype];
9433 switch(mtype)
9435 case MOVE_WALK:
9436 data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16);
9437 break;
9438 case MOVE_RUN:
9439 data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17);
9440 break;
9441 case MOVE_RUN_BACK:
9442 data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16);
9443 break;
9444 case MOVE_SWIM:
9445 data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16);
9446 break;
9447 case MOVE_SWIM_BACK:
9448 data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16);
9449 break;
9450 case MOVE_TURN_RATE:
9451 data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16);
9452 break;
9453 case MOVE_FLIGHT:
9454 data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16);
9455 break;
9456 case MOVE_FLIGHT_BACK:
9457 data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16);
9458 break;
9459 case MOVE_PITCH_RATE:
9460 data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16);
9461 break;
9462 default:
9463 sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype);
9464 return;
9466 data.append(GetPackGUID());
9467 data << (uint32)0; // moveEvent, NUM_PMOVE_EVTS = 0x39
9468 if (mtype == MOVE_RUN)
9469 data << uint8(0); // new 2.1.0
9470 data << float(GetSpeed(mtype));
9471 SendMessageToSet( &data, true );
9473 if(Pet* pet = GetPet())
9474 pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced);
9477 void Unit::SetHover(bool on)
9479 if(on)
9480 CastSpell(this, 11010, true);
9481 else
9482 RemoveAurasDueToSpell(11010);
9485 void Unit::setDeathState(DeathState s)
9487 if (s != ALIVE && s!= JUST_ALIVED)
9489 CombatStop();
9490 DeleteThreatList();
9491 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9493 if(IsNonMeleeSpellCasted(false))
9494 InterruptNonMeleeSpells(false);
9497 if (s == JUST_DIED)
9499 RemoveAllAurasOnDeath();
9500 RemoveGuardians();
9501 UnsummonAllTotems();
9503 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
9504 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
9505 // remove aurastates allowing special moves
9506 ClearAllReactives();
9507 ClearDiminishings();
9509 else if(s == JUST_ALIVED)
9511 RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
9514 if (m_deathState != ALIVE && s == ALIVE)
9516 //_ApplyAllAuraMods();
9518 m_deathState = s;
9521 /*########################################
9522 ######## ########
9523 ######## AGGRO SYSTEM ########
9524 ######## ########
9525 ########################################*/
9526 bool Unit::CanHaveThreatList() const
9528 // only creatures can have threat list
9529 if( GetTypeId() != TYPEID_UNIT )
9530 return false;
9532 // only alive units can have threat list
9533 if( !isAlive() )
9534 return false;
9536 // totems can not have threat list
9537 if( ((Creature*)this)->isTotem() )
9538 return false;
9540 // vehicles can not have threat list
9541 if( ((Creature*)this)->isVehicle() )
9542 return false;
9544 // pets can not have a threat list, unless they are controlled by a creature
9545 if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
9546 return false;
9548 return true;
9551 //======================================================================
9553 float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask)
9555 if(!HasAuraType(SPELL_AURA_MOD_THREAT))
9556 return threat;
9558 SpellSchools school = GetFirstSchoolInMask(schoolMask);
9560 return threat * m_threatModifier[school];
9563 //======================================================================
9565 void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, SpellEntry const *threatSpell)
9567 // Only mobs can manage threat lists
9568 if(CanHaveThreatList())
9569 m_ThreatManager.addThreat(pVictim, threat, schoolMask, threatSpell);
9572 //======================================================================
9574 void Unit::DeleteThreatList()
9576 m_ThreatManager.clearReferences();
9579 //======================================================================
9581 void Unit::TauntApply(Unit* taunter)
9583 assert(GetTypeId()== TYPEID_UNIT);
9585 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
9586 return;
9588 if(!CanHaveThreatList())
9589 return;
9591 Unit *target = getVictim();
9592 if(target && target == taunter)
9593 return;
9595 SetInFront(taunter);
9596 if (((Creature*)this)->AI())
9597 ((Creature*)this)->AI()->AttackStart(taunter);
9599 m_ThreatManager.tauntApply(taunter);
9602 //======================================================================
9604 void Unit::TauntFadeOut(Unit *taunter)
9606 assert(GetTypeId()== TYPEID_UNIT);
9608 if(!taunter || (taunter->GetTypeId() == TYPEID_PLAYER && ((Player*)taunter)->isGameMaster()))
9609 return;
9611 if(!CanHaveThreatList())
9612 return;
9614 Unit *target = getVictim();
9615 if(!target || target != taunter)
9616 return;
9618 if(m_ThreatManager.isThreatListEmpty())
9620 if(((Creature*)this)->AI())
9621 ((Creature*)this)->AI()->EnterEvadeMode();
9622 return;
9625 m_ThreatManager.tauntFadeOut(taunter);
9626 target = m_ThreatManager.getHostilTarget();
9628 if (target && target != taunter)
9630 SetInFront(target);
9631 if (((Creature*)this)->AI())
9632 ((Creature*)this)->AI()->AttackStart(target);
9636 //======================================================================
9638 bool Unit::SelectHostilTarget()
9640 //function provides main threat functionality
9641 //next-victim-selection algorithm and evade mode are called
9642 //threat list sorting etc.
9644 assert(GetTypeId()== TYPEID_UNIT);
9646 if (!this->isAlive())
9647 return false;
9648 //This function only useful once AI has been initialized
9649 if (!((Creature*)this)->AI())
9650 return false;
9652 Unit* target = NULL;
9654 // First checking if we have some taunt on us
9655 const AuraList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT);
9656 if ( !tauntAuras.empty() )
9658 Unit* caster;
9660 // The last taunt aura caster is alive an we are happy to attack him
9661 if ( (caster = tauntAuras.back()->GetCaster()) && caster->isAlive() )
9662 return true;
9663 else if (tauntAuras.size() > 1)
9665 // We do not have last taunt aura caster but we have more taunt auras,
9666 // so find first available target
9668 // Auras are pushed_back, last caster will be on the end
9669 AuraList::const_iterator aura = --tauntAuras.end();
9672 --aura;
9673 if ( (caster = (*aura)->GetCaster()) &&
9674 caster->IsInMap(this) && caster->isTargetableForAttack() && caster->isInAccessablePlaceFor((Creature*)this) )
9676 target = caster;
9677 break;
9679 }while (aura != tauntAuras.begin());
9683 if ( !target && !m_ThreatManager.isThreatListEmpty() )
9684 // No taunt aura or taunt aura caster is dead standart target selection
9685 target = m_ThreatManager.getHostilTarget();
9687 if(target)
9689 if(!hasUnitState(UNIT_STAT_STUNNED))
9690 SetInFront(target);
9691 ((Creature*)this)->AI()->AttackStart(target);
9692 return true;
9695 // no target but something prevent go to evade mode
9696 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) )
9697 return false;
9699 // last case when creature don't must go to evade mode:
9700 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9701 // for example at owner command to pet attack some far away creature
9702 // Note: creature not have targeted movement generator but have attacker in this case
9703 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE )
9705 for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
9707 if( (*itr)->IsInMap(this) && (*itr)->isTargetableForAttack() && (*itr)->isInAccessablePlaceFor((Creature*)this) )
9708 return false;
9712 // enter in evade mode in other case
9713 ((Creature*)this)->AI()->EnterEvadeMode();
9715 return false;
9718 //======================================================================
9719 //======================================================================
9720 //======================================================================
9722 int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_index, int32 effBasePoints, Unit const* target)
9724 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
9726 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
9728 int32 level = int32(getLevel());
9729 if (level > (int32)spellProto->maxLevel && spellProto->maxLevel > 0)
9730 level = (int32)spellProto->maxLevel;
9731 else if (level < (int32)spellProto->baseLevel)
9732 level = (int32)spellProto->baseLevel;
9733 level-= (int32)spellProto->spellLevel;
9735 float basePointsPerLevel = spellProto->EffectRealPointsPerLevel[effect_index];
9736 float randomPointsPerLevel = spellProto->EffectDicePerLevel[effect_index];
9737 int32 basePoints = int32(effBasePoints + level * basePointsPerLevel);
9738 int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel);
9739 float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index];
9741 // range can have possitive and negative values, so order its for irand
9742 int32 randvalue = int32(spellProto->EffectBaseDice[effect_index]) >= randomPoints
9743 ? irand(randomPoints, int32(spellProto->EffectBaseDice[effect_index]))
9744 : irand(int32(spellProto->EffectBaseDice[effect_index]), randomPoints);
9746 int32 value = basePoints + randvalue;
9747 //random damage
9748 if(comboDamage != 0 && unitPlayer && target && (target->GetGUID() == unitPlayer->GetComboTarget()))
9749 value += (int32)(comboDamage * comboPoints);
9751 if(Player* modOwner = GetSpellModOwner())
9753 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_ALL_EFFECTS, value);
9754 switch(effect_index)
9756 case 0:
9757 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT1, value);
9758 break;
9759 case 1:
9760 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT2, value);
9761 break;
9762 case 2:
9763 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_EFFECT3, value);
9764 break;
9768 if(spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel &&
9769 spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE &&
9770 spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK)
9771 value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
9773 return value;
9776 int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_index, Unit const* target)
9778 Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
9780 uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
9782 int32 minduration = GetSpellDuration(spellProto);
9783 int32 maxduration = GetSpellMaxDuration(spellProto);
9785 int32 duration;
9787 if( minduration != -1 && minduration != maxduration )
9788 duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
9789 else
9790 duration = minduration;
9792 if (duration > 0)
9794 int32 mechanic = GetEffectMechanic(spellProto, effect_index);
9795 // Find total mod value (negative bonus)
9796 int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
9797 // Modify from SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL aura (stack always ?)
9798 durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
9799 // Find max mod (negative bonus)
9800 int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
9802 int32 durationMod = 0;
9803 // Select strongest negative mod
9804 if (durationMod_always > durationMod_not_stack)
9805 durationMod = durationMod_not_stack;
9806 else
9807 durationMod = durationMod_always;
9809 if (durationMod != 0)
9810 duration = int32(int64(duration) * (100+durationMod) /100);
9812 if (duration < 0) duration = 0;
9815 return duration;
9818 DiminishingLevels Unit::GetDiminishing(DiminishingGroup group)
9820 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9822 if(i->DRGroup != group)
9823 continue;
9825 if(!i->hitCount)
9826 return DIMINISHING_LEVEL_1;
9828 if(!i->hitTime)
9829 return DIMINISHING_LEVEL_1;
9831 // If last spell was casted more than 15 seconds ago - reset the count.
9832 if(i->stack==0 && getMSTimeDiff(i->hitTime,getMSTime()) > 15000)
9834 i->hitCount = DIMINISHING_LEVEL_1;
9835 return DIMINISHING_LEVEL_1;
9837 // or else increase the count.
9838 else
9840 return DiminishingLevels(i->hitCount);
9843 return DIMINISHING_LEVEL_1;
9846 void Unit::IncrDiminishing(DiminishingGroup group)
9848 // Checking for existing in the table
9849 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9851 if(i->DRGroup != group)
9852 continue;
9853 if(i->hitCount < DIMINISHING_LEVEL_IMMUNE)
9854 i->hitCount += 1;
9855 return;
9857 m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
9860 void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level)
9862 if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) )
9863 return;
9865 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9866 if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group))
9868 // test pet/charm masters instead pets/charmeds
9869 Unit const* targetOwner = GetCharmerOrOwner();
9870 Unit const* casterOwner = caster->GetCharmerOrOwner();
9872 Unit const* target = targetOwner ? targetOwner : this;
9873 Unit const* source = casterOwner ? casterOwner : caster;
9875 if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
9876 duration = 10000;
9879 float mod = 1.0f;
9881 // Some diminishings applies to mobs too (for example, Stun)
9882 if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && GetTypeId() == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
9884 DiminishingLevels diminish = Level;
9885 switch(diminish)
9887 case DIMINISHING_LEVEL_1: break;
9888 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
9889 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
9890 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f;break;
9891 default: break;
9895 duration = int32(duration * mod);
9898 void Unit::ApplyDiminishingAura( DiminishingGroup group, bool apply )
9900 // Checking for existing in the table
9901 for(Diminishing::iterator i = m_Diminishing.begin(); i != m_Diminishing.end(); ++i)
9903 if(i->DRGroup != group)
9904 continue;
9906 if(apply)
9907 i->stack += 1;
9908 else if(i->stack)
9910 i->stack -= 1;
9911 // Remember time after last aura from group removed
9912 if (i->stack == 0)
9913 i->hitTime = getMSTime();
9915 break;
9919 Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
9921 return ObjectAccessor::GetUnit(object,guid);
9924 bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const
9926 return isVisibleForOrDetect(u, false, inVisibleList, false);
9929 uint32 Unit::GetCreatureType() const
9931 if(GetTypeId() == TYPEID_PLAYER)
9933 SpellShapeshiftEntry const* ssEntry = sSpellShapeshiftStore.LookupEntry(m_form);
9934 if(ssEntry && ssEntry->creatureType > 0)
9935 return ssEntry->creatureType;
9936 else
9937 return CREATURE_TYPE_HUMANOID;
9939 else
9940 return ((Creature*)this)->GetCreatureInfo()->type;
9943 /*#######################################
9944 ######## ########
9945 ######## STAT SYSTEM ########
9946 ######## ########
9947 #######################################*/
9949 bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply)
9951 if(unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
9953 sLog.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9954 return false;
9957 float val = 1.0f;
9959 switch(modifierType)
9961 case BASE_VALUE:
9962 case TOTAL_VALUE:
9963 m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9964 break;
9965 case BASE_PCT:
9966 case TOTAL_PCT:
9967 if(amount <= -100.0f) //small hack-fix for -100% modifiers
9968 amount = -200.0f;
9970 val = (100.0f + amount) / 100.0f;
9971 m_auraModifiersGroup[unitMod][modifierType] *= apply ? val : (1.0f/val);
9972 break;
9974 default:
9975 break;
9978 if(!CanModifyStats())
9979 return false;
9981 switch(unitMod)
9983 case UNIT_MOD_STAT_STRENGTH:
9984 case UNIT_MOD_STAT_AGILITY:
9985 case UNIT_MOD_STAT_STAMINA:
9986 case UNIT_MOD_STAT_INTELLECT:
9987 case UNIT_MOD_STAT_SPIRIT: UpdateStats(GetStatByAuraGroup(unitMod)); break;
9989 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9990 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9992 case UNIT_MOD_MANA:
9993 case UNIT_MOD_RAGE:
9994 case UNIT_MOD_FOCUS:
9995 case UNIT_MOD_ENERGY:
9996 case UNIT_MOD_HAPPINESS:
9997 case UNIT_MOD_RUNE:
9998 case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break;
10000 case UNIT_MOD_RESISTANCE_HOLY:
10001 case UNIT_MOD_RESISTANCE_FIRE:
10002 case UNIT_MOD_RESISTANCE_NATURE:
10003 case UNIT_MOD_RESISTANCE_FROST:
10004 case UNIT_MOD_RESISTANCE_SHADOW:
10005 case UNIT_MOD_RESISTANCE_ARCANE: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod)); break;
10007 case UNIT_MOD_ATTACK_POWER: UpdateAttackPowerAndDamage(); break;
10008 case UNIT_MOD_ATTACK_POWER_RANGED: UpdateAttackPowerAndDamage(true); break;
10010 case UNIT_MOD_DAMAGE_MAINHAND: UpdateDamagePhysical(BASE_ATTACK); break;
10011 case UNIT_MOD_DAMAGE_OFFHAND: UpdateDamagePhysical(OFF_ATTACK); break;
10012 case UNIT_MOD_DAMAGE_RANGED: UpdateDamagePhysical(RANGED_ATTACK); break;
10014 default:
10015 break;
10018 return true;
10021 float Unit::GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const
10023 if( unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_END)
10025 sLog.outError("trial to access non existed modifier value from UnitMods!");
10026 return 0.0f;
10029 if(modifierType == TOTAL_PCT && m_auraModifiersGroup[unitMod][modifierType] <= 0.0f)
10030 return 0.0f;
10032 return m_auraModifiersGroup[unitMod][modifierType];
10035 float Unit::GetTotalStatValue(Stats stat) const
10037 UnitMods unitMod = UnitMods(UNIT_MOD_STAT_START + stat);
10039 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
10040 return 0.0f;
10042 // value = ((base_value * base_pct) + total_value) * total_pct
10043 float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat);
10044 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
10045 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
10046 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
10048 return value;
10051 float Unit::GetTotalAuraModValue(UnitMods unitMod) const
10053 if(unitMod >= UNIT_MOD_END)
10055 sLog.outError("trial to access non existed UnitMods in GetTotalAuraModValue()!");
10056 return 0.0f;
10059 if(m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f)
10060 return 0.0f;
10062 float value = m_auraModifiersGroup[unitMod][BASE_VALUE];
10063 value *= m_auraModifiersGroup[unitMod][BASE_PCT];
10064 value += m_auraModifiersGroup[unitMod][TOTAL_VALUE];
10065 value *= m_auraModifiersGroup[unitMod][TOTAL_PCT];
10067 return value;
10070 SpellSchools Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod) const
10072 SpellSchools school = SPELL_SCHOOL_NORMAL;
10074 switch(unitMod)
10076 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
10077 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
10078 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
10079 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
10080 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
10081 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
10083 default:
10084 break;
10087 return school;
10090 Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const
10092 Stats stat = STAT_STRENGTH;
10094 switch(unitMod)
10096 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
10097 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
10098 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
10099 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
10100 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
10102 default:
10103 break;
10106 return stat;
10109 Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const
10111 switch(unitMod)
10113 case UNIT_MOD_MANA: return POWER_MANA;
10114 case UNIT_MOD_RAGE: return POWER_RAGE;
10115 case UNIT_MOD_FOCUS: return POWER_FOCUS;
10116 case UNIT_MOD_ENERGY: return POWER_ENERGY;
10117 case UNIT_MOD_HAPPINESS: return POWER_HAPPINESS;
10118 case UNIT_MOD_RUNE: return POWER_RUNE;
10119 case UNIT_MOD_RUNIC_POWER:return POWER_RUNIC_POWER;
10120 default: return POWER_MANA;
10123 return POWER_MANA;
10126 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const
10128 if (attType == RANGED_ATTACK)
10130 int32 ap = GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS);
10131 if (ap < 0)
10132 return 0.0f;
10133 return ap * (1.0f + GetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER));
10135 else
10137 int32 ap = GetInt32Value(UNIT_FIELD_ATTACK_POWER) + GetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS);
10138 if (ap < 0)
10139 return 0.0f;
10140 return ap * (1.0f + GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER));
10144 float Unit::GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const
10146 if (attType == OFF_ATTACK && !haveOffhandWeapon())
10147 return 0.0f;
10149 return m_weaponDamage[attType][type];
10152 void Unit::SetLevel(uint32 lvl)
10154 SetUInt32Value(UNIT_FIELD_LEVEL, lvl);
10156 // group update
10157 if ((GetTypeId() == TYPEID_PLAYER) && ((Player*)this)->GetGroup())
10158 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
10161 void Unit::SetHealth(uint32 val)
10163 uint32 maxHealth = GetMaxHealth();
10164 if(maxHealth < val)
10165 val = maxHealth;
10167 SetUInt32Value(UNIT_FIELD_HEALTH, val);
10169 // group update
10170 if(GetTypeId() == TYPEID_PLAYER)
10172 if(((Player*)this)->GetGroup())
10173 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
10175 else if(((Creature*)this)->isPet())
10177 Pet *pet = ((Pet*)this);
10178 if(pet->isControlled())
10180 Unit *owner = GetOwner();
10181 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10182 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
10187 void Unit::SetMaxHealth(uint32 val)
10189 uint32 health = GetHealth();
10190 SetUInt32Value(UNIT_FIELD_MAXHEALTH, val);
10192 // group update
10193 if(GetTypeId() == TYPEID_PLAYER)
10195 if(((Player*)this)->GetGroup())
10196 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP);
10198 else if(((Creature*)this)->isPet())
10200 Pet *pet = ((Pet*)this);
10201 if(pet->isControlled())
10203 Unit *owner = GetOwner();
10204 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10205 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
10209 if(val < health)
10210 SetHealth(val);
10213 void Unit::SetPower(Powers power, uint32 val)
10215 if(GetPower(power) == val)
10216 return;
10218 uint32 maxPower = GetMaxPower(power);
10219 if(maxPower < val)
10220 val = maxPower;
10222 SetStatInt32Value(UNIT_FIELD_POWER1 + power, val);
10224 WorldPacket data(SMSG_POWER_UPDATE);
10225 data.append(GetPackGUID());
10226 data << uint8(power);
10227 data << uint32(val);
10228 SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER ? true : false);
10230 // group update
10231 if(GetTypeId() == TYPEID_PLAYER)
10233 if(((Player*)this)->GetGroup())
10234 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
10236 else if(((Creature*)this)->isPet())
10238 Pet *pet = ((Pet*)this);
10239 if(pet->isControlled())
10241 Unit *owner = GetOwner();
10242 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10243 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
10246 // Update the pet's character sheet with happiness damage bonus
10247 if(pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
10249 pet->UpdateDamagePhysical(BASE_ATTACK);
10254 void Unit::SetMaxPower(Powers power, uint32 val)
10256 uint32 cur_power = GetPower(power);
10257 SetStatInt32Value(UNIT_FIELD_MAXPOWER1 + power, val);
10259 // group update
10260 if(GetTypeId() == TYPEID_PLAYER)
10262 if(((Player*)this)->GetGroup())
10263 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
10265 else if(((Creature*)this)->isPet())
10267 Pet *pet = ((Pet*)this);
10268 if(pet->isControlled())
10270 Unit *owner = GetOwner();
10271 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10272 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
10276 if(val < cur_power)
10277 SetPower(power, val);
10280 void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
10282 ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
10284 // group update
10285 if(GetTypeId() == TYPEID_PLAYER)
10287 if(((Player*)this)->GetGroup())
10288 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
10290 else if(((Creature*)this)->isPet())
10292 Pet *pet = ((Pet*)this);
10293 if(pet->isControlled())
10295 Unit *owner = GetOwner();
10296 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10297 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
10302 void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
10304 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
10306 // group update
10307 if(GetTypeId() == TYPEID_PLAYER)
10309 if(((Player*)this)->GetGroup())
10310 ((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
10312 else if(((Creature*)this)->isPet())
10314 Pet *pet = ((Pet*)this);
10315 if(pet->isControlled())
10317 Unit *owner = GetOwner();
10318 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
10319 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
10324 void Unit::ApplyAuraProcTriggerDamage( Aura* aura, bool apply )
10326 AuraList& tAuraProcTriggerDamage = m_modAuras[SPELL_AURA_PROC_TRIGGER_DAMAGE];
10327 if(apply)
10328 tAuraProcTriggerDamage.push_back(aura);
10329 else
10330 tAuraProcTriggerDamage.remove(aura);
10333 uint32 Unit::GetCreatePowers( Powers power ) const
10335 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
10336 switch(power)
10338 case POWER_MANA: return GetCreateMana();
10339 case POWER_RAGE: return 1000;
10340 case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100);
10341 case POWER_ENERGY: return 100;
10342 case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000);
10343 case POWER_RUNIC_POWER: return 1000;
10344 case POWER_RUNE: return 0;
10345 case POWER_HEALTH: return 0;
10348 return 0;
10351 void Unit::AddToWorld()
10353 Object::AddToWorld();
10356 void Unit::RemoveFromWorld()
10358 // cleanup
10359 if(IsInWorld())
10361 RemoveNotOwnSingleTargetAuras();
10362 RemoveGuardians();
10365 Object::RemoveFromWorld();
10368 void Unit::CleanupsBeforeDelete()
10370 if(m_uint32Values) // only for fully created object
10372 InterruptNonMeleeSpells(true);
10373 m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
10374 CombatStop();
10375 ClearComboPointHolders();
10376 DeleteThreatList();
10377 getHostilRefManager().setOnlineOfflineState(false);
10378 RemoveAllAuras();
10379 RemoveAllGameObjects();
10380 RemoveAllDynObjects();
10381 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
10383 RemoveFromWorld();
10386 CharmInfo* Unit::InitCharmInfo(Unit *charm)
10388 if(!m_charmInfo)
10389 m_charmInfo = new CharmInfo(charm);
10390 return m_charmInfo;
10393 CharmInfo::CharmInfo(Unit* unit)
10394 : m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0)
10396 for(int i =0; i<4; ++i)
10398 m_charmspells[i].spellId = 0;
10399 m_charmspells[i].active = ACT_DISABLED;
10403 void CharmInfo::InitPetActionBar()
10405 // the first 3 SpellOrActions are attack, follow and stay
10406 for(uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_START - ACTION_BAR_INDEX_START; ++i)
10407 SetActionBar(ACTION_BAR_INDEX_START + i,COMMAND_ATTACK - i,ACT_COMMAND);
10409 // middle 4 SpellOrActions are spells/special attacks/abilities
10410 for(uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START; ++i)
10411 SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i,0,ACT_DISABLED);
10413 // last 3 SpellOrActions are reactions
10414 for(uint32 i = 0; i < ACTION_BAR_INDEX_END - ACTION_BAR_INDEX_PET_SPELL_END; ++i)
10415 SetActionBar(ACTION_BAR_INDEX_PET_SPELL_END + i,COMMAND_ATTACK - i,ACT_REACTION);
10418 void CharmInfo::InitEmptyActionBar()
10420 SetActionBar(ACTION_BAR_INDEX_START,COMMAND_ATTACK,ACT_COMMAND);
10421 for(uint32 x = ACTION_BAR_INDEX_START+1; x < ACTION_BAR_INDEX_END; ++x)
10422 SetActionBar(x,0,ACT_PASSIVE);
10425 void CharmInfo::InitPossessCreateSpells()
10427 InitEmptyActionBar(); //charm action bar
10429 if(m_unit->GetTypeId() == TYPEID_PLAYER) //possessed players don't have spells, keep the action bar empty
10430 return;
10432 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
10434 if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
10435 m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
10436 else
10437 AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE);
10441 void CharmInfo::InitCharmCreateSpells()
10443 if(m_unit->GetTypeId() == TYPEID_PLAYER) //charmed players don't have spells
10445 InitEmptyActionBar();
10446 return;
10449 InitPetActionBar();
10451 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
10453 uint32 spellId = ((Creature*)m_unit)->m_spells[x];
10454 m_charmspells[x].spellId = spellId;
10456 if(!spellId)
10457 continue;
10459 if (IsPassiveSpell(spellId))
10461 m_unit->CastSpell(m_unit, spellId, true);
10462 m_charmspells[x].active = ACT_PASSIVE;
10464 else
10466 ActiveStates newstate;
10467 bool onlyselfcast = true;
10468 SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
10470 if(!spellInfo) onlyselfcast = false;
10471 for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
10473 if(spellInfo->EffectImplicitTargetA[i] != TARGET_SELF && spellInfo->EffectImplicitTargetA[i] != 0)
10474 onlyselfcast = false;
10477 if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable
10478 newstate = ACT_DISABLED;
10479 else
10480 newstate = ACT_PASSIVE;
10482 AddSpellToActionBar(spellId, newstate);
10487 bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
10489 uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id);
10491 // new spell rank can be already listed
10492 for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
10494 if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
10496 if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
10498 PetActionBar[i].SpellOrAction = spell_id;
10499 return true;
10504 // or use empty slot in other case
10505 for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
10507 if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
10509 SetActionBar(i,spell_id,newstate == ACT_DECIDE ? ACT_DISABLED : newstate);
10510 return true;
10513 return false;
10516 bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
10518 uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id);
10520 for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
10522 if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
10524 if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
10526 SetActionBar(i,0,ACT_DISABLED);
10527 return true;
10532 return false;
10535 void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
10537 if(IsPassiveSpell(spellid))
10538 return;
10540 for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x)
10542 if(spellid == m_charmspells[x].spellId)
10544 m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
10549 void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
10551 m_petnumber = petnumber;
10552 if(statwindow)
10553 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
10554 else
10555 m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
10558 void CharmInfo::LoadPetActionBar(const std::string& data )
10560 InitPetActionBar();
10562 Tokens tokens = StrSplit(data, " ");
10564 if (tokens.size() != (ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START)*2)
10565 return; // non critical, will reset to default
10567 int index;
10568 Tokens::iterator iter;
10569 for(iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index )
10571 // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
10572 PetActionBar[index].Type = atol((*iter).c_str());
10573 ++iter;
10574 PetActionBar[index].SpellOrAction = atol((*iter).c_str());
10576 // check correctness
10577 if(PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction))
10578 SetActionBar(index,0,ACT_DISABLED);
10582 void CharmInfo::BuildActionBar( WorldPacket* data )
10584 for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
10586 *data << uint16(PetActionBar[i].SpellOrAction);
10587 *data << uint16(PetActionBar[i].Type);
10591 void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state )
10593 for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
10595 if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
10597 PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED;
10598 break;
10603 bool Unit::isFrozen() const
10605 return HasAuraState(AURA_STATE_FROZEN);
10608 struct ProcTriggeredData
10610 ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura)
10611 : spellProcEvent(_spellProcEvent), triggeredByAura(_triggeredByAura),
10612 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex()))
10614 SpellProcEventEntry const *spellProcEvent;
10615 Aura* triggeredByAura;
10616 Unit::spellEffectPair triggeredByAura_SpellPair;
10619 typedef std::list< ProcTriggeredData > ProcTriggeredList;
10620 typedef std::list< uint32> RemoveSpellList;
10622 // List of auras that CAN be trigger but may not exist in spell_proc_event
10623 // in most case need for drop charges
10624 // in some types of aura need do additional check
10625 // for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
10626 bool InitTriggerAuraData()
10628 for (int i=0;i<TOTAL_AURAS;++i)
10630 isTriggerAura[i]=false;
10631 isNonTriggerAura[i] = false;
10633 isTriggerAura[SPELL_AURA_DUMMY] = true;
10634 isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
10635 isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
10636 isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura not have charges but need remove him on trigger
10637 isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
10638 isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
10639 isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
10640 isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
10641 isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
10642 isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
10643 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
10644 isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
10645 isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
10646 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
10647 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
10648 isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
10649 isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
10650 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
10651 isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
10652 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
10653 isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
10654 isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
10655 isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
10656 isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
10657 isTriggerAura[SPELL_AURA_MOD_HASTE] = true;
10658 isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE]=true;
10659 isTriggerAura[SPELL_AURA_PRAYER_OF_MENDING] = true;
10660 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
10661 isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true;
10662 isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
10664 isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true;
10665 isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK]=true;
10667 return true;
10670 uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
10672 uint32 procEx = PROC_EX_NONE;
10673 // Check victim state
10674 if (missCondition!=SPELL_MISS_NONE)
10675 switch (missCondition)
10677 case SPELL_MISS_MISS: procEx|=PROC_EX_MISS; break;
10678 case SPELL_MISS_RESIST: procEx|=PROC_EX_RESIST; break;
10679 case SPELL_MISS_DODGE: procEx|=PROC_EX_DODGE; break;
10680 case SPELL_MISS_PARRY: procEx|=PROC_EX_PARRY; break;
10681 case SPELL_MISS_BLOCK: procEx|=PROC_EX_BLOCK; break;
10682 case SPELL_MISS_EVADE: procEx|=PROC_EX_EVADE; break;
10683 case SPELL_MISS_IMMUNE: procEx|=PROC_EX_IMMUNE; break;
10684 case SPELL_MISS_IMMUNE2: procEx|=PROC_EX_IMMUNE; break;
10685 case SPELL_MISS_DEFLECT: procEx|=PROC_EX_DEFLECT;break;
10686 case SPELL_MISS_ABSORB: procEx|=PROC_EX_ABSORB; break;
10687 case SPELL_MISS_REFLECT: procEx|=PROC_EX_REFLECT;break;
10688 default:
10689 break;
10691 else
10693 // On block
10694 if (damageInfo->blocked)
10695 procEx|=PROC_EX_BLOCK;
10696 // On absorb
10697 if (damageInfo->absorb)
10698 procEx|=PROC_EX_ABSORB;
10699 // On crit
10700 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10701 procEx|=PROC_EX_CRITICAL_HIT;
10702 else
10703 procEx|=PROC_EX_NORMAL_HIT;
10705 return procEx;
10708 void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
10710 // For melee/ranged based attack need update skills and set some Aura states
10711 if (procFlag & MELEE_BASED_TRIGGER_MASK)
10713 // Update skills here for players
10714 if (GetTypeId() == TYPEID_PLAYER)
10716 // On melee based hit/miss/resist need update skill (for victim and attacker)
10717 if (procExtra&(PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST))
10719 if (pTarget->GetTypeId() != TYPEID_PLAYER && pTarget->GetCreatureType() != CREATURE_TYPE_CRITTER)
10720 ((Player*)this)->UpdateCombatSkills(pTarget, attType, isVictim);
10722 // Update defence if player is victim and parry/dodge/block
10723 if (isVictim && procExtra&(PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK))
10724 ((Player*)this)->UpdateDefense();
10726 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10727 if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK))
10729 // for victim
10730 if (isVictim)
10732 // if victim and dodge attack
10733 if (procExtra&PROC_EX_DODGE)
10735 //Update AURA_STATE on dodge
10736 if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
10738 ModifyAuraState(AURA_STATE_DEFENSE, true);
10739 StartReactiveTimer( REACTIVE_DEFENSE );
10742 // if victim and parry attack
10743 if (procExtra & PROC_EX_PARRY)
10745 // For Hunters only Counterattack (skip Mongoose bite)
10746 if (getClass() == CLASS_HUNTER)
10748 ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
10749 StartReactiveTimer( REACTIVE_HUNTER_PARRY );
10751 else
10753 ModifyAuraState(AURA_STATE_DEFENSE, true);
10754 StartReactiveTimer( REACTIVE_DEFENSE );
10757 // if and victim block attack
10758 if (procExtra & PROC_EX_BLOCK)
10760 ModifyAuraState(AURA_STATE_DEFENSE,true);
10761 StartReactiveTimer( REACTIVE_DEFENSE );
10764 else //For attacker
10766 // Overpower on victim dodge
10767 if (procExtra&PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
10769 ((Player*)this)->AddComboPoints(pTarget, 1);
10770 StartReactiveTimer( REACTIVE_OVERPOWER );
10776 RemoveSpellList removedSpells;
10777 ProcTriggeredList procTriggered;
10778 // Fill procTriggered list
10779 for(AuraMap::const_iterator itr = GetAuras().begin(); itr!= GetAuras().end(); ++itr)
10781 SpellProcEventEntry const* spellProcEvent = NULL;
10782 if(!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent))
10783 continue;
10785 procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) );
10788 // Nothing found
10789 if (procTriggered.empty())
10790 return;
10792 // Handle effects proceed this time
10793 for(ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
10795 // Some auras can be deleted in function called in this loop (except first, ofc)
10796 // Until storing auars in std::multimap to hard check deleting by another way
10797 if(i != procTriggered.begin())
10799 bool found = false;
10800 AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
10801 AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
10802 for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
10804 if(itr->second==i->triggeredByAura)
10806 found = true;
10807 break;
10810 if(!found)
10812 // sLog.outDebug("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler", i->triggeredByAura->GetModifier()->m_auraname, i->triggeredByAura_SpellPair.first, i->triggeredByAura_SpellPair.second);
10813 // sLog.outDebug("It can be deleted one from early proccesed auras:");
10814 // for(ProcTriggeredList::const_iterator i2 = procTriggered.begin(); i != i2; ++i2)
10815 // sLog.outDebug(" Spell aura %u (id:%u effect:%u)", i->triggeredByAura->GetModifier()->m_auraname,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
10816 // sLog.outDebug(" <end of list>");
10817 continue;
10821 SpellProcEventEntry const *spellProcEvent = i->spellProcEvent;
10822 Aura *triggeredByAura = i->triggeredByAura;
10823 Modifier *auraModifier = triggeredByAura->GetModifier();
10824 SpellEntry const *spellInfo = triggeredByAura->GetSpellProto();
10825 bool useCharges = triggeredByAura->GetAuraCharges() > 0;
10826 // For players set spell cooldown if need
10827 uint32 cooldown = 0;
10828 if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
10829 cooldown = spellProcEvent->cooldown;
10831 switch(auraModifier->m_auraname)
10833 case SPELL_AURA_PROC_TRIGGER_SPELL:
10835 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10836 // Don`t drop charge or add cooldown for not started trigger
10837 if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
10838 continue;
10839 break;
10841 case SPELL_AURA_PROC_TRIGGER_DAMAGE:
10843 sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10844 SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
10845 CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);
10846 DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
10847 SendSpellNonMeleeDamageLog(&damageInfo);
10848 DealSpellDamage(&damageInfo, true);
10849 break;
10851 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
10852 case SPELL_AURA_MANA_SHIELD:
10853 case SPELL_AURA_OBS_MOD_MANA:
10854 case SPELL_AURA_DUMMY:
10856 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10857 if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
10858 continue;
10859 break;
10861 case SPELL_AURA_MOD_HASTE:
10863 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10864 if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
10865 continue;
10866 break;
10868 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
10870 sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10871 if (!HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown))
10872 continue;
10873 break;
10875 case SPELL_AURA_PRAYER_OF_MENDING:
10877 sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10878 (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
10880 HandleMeandingAuraProc(triggeredByAura);
10881 break;
10883 case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
10885 sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
10887 if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
10888 continue;
10889 break;
10891 case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
10892 // Skip melee hits or instant cast spells
10893 if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
10894 continue;
10895 break;
10896 case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
10897 // Skip Melee hits and spells ws wrong school
10898 if (procSpell == NULL || (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0)
10899 continue;
10900 break;
10901 case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
10902 case SPELL_AURA_MOD_POWER_COST_SCHOOL:
10903 // Skip melee hits and spells ws wrong school or zero cost
10904 if (procSpell == NULL ||
10905 (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
10906 (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) // School check
10907 continue;
10908 break;
10909 case SPELL_AURA_MECHANIC_IMMUNITY:
10910 // Compare mechanic
10911 if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
10912 continue;
10913 break;
10914 case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
10915 // Compare mechanic
10916 if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
10917 continue;
10918 break;
10919 case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
10920 // Compare casters
10921 if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID())
10922 continue;
10923 break;
10924 case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
10925 if (!procSpell)
10926 continue;
10927 break;
10928 default:
10929 // nothing do, just charges counter
10930 break;
10932 // Remove charge (aura can be removed by triggers)
10933 if(useCharges)
10935 // need found aura on drop (can be dropped by triggers)
10936 AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
10937 AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
10938 for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
10940 // If last charge dropped add spell to remove list
10941 if(itr->second == i->triggeredByAura && triggeredByAura->DropAuraCharge())
10943 removedSpells.push_back(triggeredByAura->GetId());
10944 break;
10949 if (!removedSpells.empty())
10951 // Sort spells and remove dublicates
10952 removedSpells.sort();
10953 removedSpells.unique();
10954 // Remove auras from removedAuras
10955 for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();++i)
10956 RemoveAurasDueToSpell(*i);
10960 SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
10962 return SPELL_SCHOOL_MASK_NORMAL;
10965 Player* Unit::GetSpellModOwner()
10967 if(GetTypeId()==TYPEID_PLAYER)
10968 return (Player*)this;
10969 if(((Creature*)this)->isPet() || ((Creature*)this)->isTotem())
10971 Unit* owner = GetOwner();
10972 if(owner && owner->GetTypeId()==TYPEID_PLAYER)
10973 return (Player*)owner;
10975 return NULL;
10978 ///----------Pet responses methods-----------------
10979 void Unit::SendPetCastFail(uint32 spellid, SpellCastResult msg)
10981 if(msg == SPELL_CAST_OK)
10982 return;
10984 Unit *owner = GetCharmerOrOwner();
10985 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
10986 return;
10988 WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1);
10989 data << uint8(0); // cast count?
10990 data << uint32(spellid);
10991 data << uint8(msg);
10992 // uint32 for some reason
10993 // uint32 for some reason
10994 ((Player*)owner)->GetSession()->SendPacket(&data);
10997 void Unit::SendPetActionFeedback (uint8 msg)
10999 Unit* owner = GetOwner();
11000 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
11001 return;
11003 WorldPacket data(SMSG_PET_ACTION_FEEDBACK, 1);
11004 data << uint8(msg);
11005 ((Player*)owner)->GetSession()->SendPacket(&data);
11008 void Unit::SendPetTalk (uint32 pettalk)
11010 Unit* owner = GetOwner();
11011 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
11012 return;
11014 WorldPacket data(SMSG_PET_ACTION_SOUND, 8 + 4);
11015 data << uint64(GetGUID());
11016 data << uint32(pettalk);
11017 ((Player*)owner)->GetSession()->SendPacket(&data);
11020 void Unit::SendPetAIReaction(uint64 guid)
11022 Unit* owner = GetOwner();
11023 if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
11024 return;
11026 WorldPacket data(SMSG_AI_REACTION, 8 + 4);
11027 data << uint64(guid);
11028 data << uint32(AI_REACTION_AGGRO);
11029 ((Player*)owner)->GetSession()->SendPacket(&data);
11032 ///----------End of Pet responses methods----------
11034 void Unit::StopMoving()
11036 clearUnitState(UNIT_STAT_MOVING);
11038 // send explicit stop packet
11039 // rely on vmaps here because for example stormwind is in air
11040 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
11041 //if (fabs(GetPositionZ() - z) < 2.0f)
11042 // Relocate(GetPositionX(), GetPositionY(), z);
11043 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
11045 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, 0, 0);
11047 // update position and orientation;
11048 WorldPacket data;
11049 BuildHeartBeatMsg(&data);
11050 SendMessageToSet(&data,false);
11053 void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID, uint32 time)
11055 if( apply )
11057 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING))
11058 return;
11060 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
11062 GetMotionMaster()->MovementExpired(false);
11063 CastStop(GetGUID()==casterGUID ? spellID : 0);
11065 Unit* caster = ObjectAccessor::GetUnit(*this,casterGUID);
11067 GetMotionMaster()->MoveFleeing(caster, time); // caster==NULL processed in MoveFleeing
11069 else
11071 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
11073 GetMotionMaster()->MovementExpired(false);
11075 if( GetTypeId() != TYPEID_PLAYER && isAlive() )
11077 // restore appropriate movement generator
11078 if(getVictim())
11079 GetMotionMaster()->MoveChase(getVictim());
11080 else
11081 GetMotionMaster()->Initialize();
11083 // attack caster if can
11084 Unit* caster = ObjectAccessor::GetObjectInWorld(casterGUID, (Unit*)NULL);
11085 if(caster && ((Creature*)this)->AI())
11086 ((Creature*)this)->AI()->AttackedBy(caster);
11090 if (GetTypeId() == TYPEID_PLAYER)
11091 ((Player*)this)->SetClientControl(this, !apply);
11094 void Unit::SetConfused(bool apply, uint64 casterGUID, uint32 spellID)
11096 if( apply )
11098 SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
11100 CastStop(GetGUID()==casterGUID ? spellID : 0);
11102 GetMotionMaster()->MoveConfused();
11104 else
11106 RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
11108 GetMotionMaster()->MovementExpired(false);
11110 if (GetTypeId() == TYPEID_UNIT)
11112 // if in combat restore movement generator
11113 if(getVictim())
11114 GetMotionMaster()->MoveChase(getVictim());
11118 if(GetTypeId() == TYPEID_PLAYER)
11119 ((Player*)this)->SetClientControl(this, !apply);
11122 bool Unit::IsSitState() const
11124 uint8 s = getStandState();
11125 return
11126 s == UNIT_STAND_STATE_SIT_CHAIR || s == UNIT_STAND_STATE_SIT_LOW_CHAIR ||
11127 s == UNIT_STAND_STATE_SIT_MEDIUM_CHAIR || s == UNIT_STAND_STATE_SIT_HIGH_CHAIR ||
11128 s == UNIT_STAND_STATE_SIT;
11131 bool Unit::IsStandState() const
11133 uint8 s = getStandState();
11134 return !IsSitState() && s != UNIT_STAND_STATE_SLEEP && s != UNIT_STAND_STATE_KNEEL;
11137 void Unit::SetStandState(uint8 state)
11139 SetByteValue(UNIT_FIELD_BYTES_1, 0, state);
11141 if (IsStandState())
11142 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED);
11144 if(GetTypeId()==TYPEID_PLAYER)
11146 WorldPacket data(SMSG_STANDSTATE_UPDATE, 1);
11147 data << (uint8)state;
11148 ((Player*)this)->GetSession()->SendPacket(&data);
11152 bool Unit::IsPolymorphed() const
11154 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH;
11157 void Unit::SetDisplayId(uint32 modelId)
11159 SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId);
11161 if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
11163 Pet *pet = ((Pet*)this);
11164 if(!pet->isControlled())
11165 return;
11166 Unit *owner = GetOwner();
11167 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
11168 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID);
11172 void Unit::ClearComboPointHolders()
11174 while(!m_ComboPointHolders.empty())
11176 uint32 lowguid = *m_ComboPointHolders.begin();
11178 Player* plr = objmgr.GetPlayer(MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER));
11179 if(plr && plr->GetComboTarget()==GetGUID()) // recheck for safe
11180 plr->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
11181 else
11182 m_ComboPointHolders.erase(lowguid); // or remove manually
11186 void Unit::ClearAllReactives()
11188 for(int i=0; i < MAX_REACTIVE; ++i)
11189 m_reactiveTimer[i] = 0;
11191 if (HasAuraState( AURA_STATE_DEFENSE))
11192 ModifyAuraState(AURA_STATE_DEFENSE, false);
11193 if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY))
11194 ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
11195 if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
11196 ((Player*)this)->ClearComboPoints();
11199 void Unit::UpdateReactives( uint32 p_time )
11201 for(int i = 0; i < MAX_REACTIVE; ++i)
11203 ReactiveType reactive = ReactiveType(i);
11205 if(!m_reactiveTimer[reactive])
11206 continue;
11208 if ( m_reactiveTimer[reactive] <= p_time)
11210 m_reactiveTimer[reactive] = 0;
11212 switch ( reactive )
11214 case REACTIVE_DEFENSE:
11215 if (HasAuraState(AURA_STATE_DEFENSE))
11216 ModifyAuraState(AURA_STATE_DEFENSE, false);
11217 break;
11218 case REACTIVE_HUNTER_PARRY:
11219 if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY))
11220 ModifyAuraState(AURA_STATE_HUNTER_PARRY, false);
11221 break;
11222 case REACTIVE_OVERPOWER:
11223 if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER)
11224 ((Player*)this)->ClearComboPoints();
11225 break;
11226 default:
11227 break;
11230 else
11232 m_reactiveTimer[reactive] -= p_time;
11237 Unit* Unit::SelectNearbyTarget() const
11239 CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
11240 Cell cell(p);
11241 cell.data.Part.reserved = ALL_DISTRICT;
11242 cell.SetNoCreate();
11244 std::list<Unit *> targets;
11247 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE);
11248 MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck> searcher(this, targets, u_check);
11250 TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
11251 TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
11253 CellLock<GridReadGuard> cell_lock(cell, p);
11254 cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
11255 cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
11258 // remove current target
11259 if(getVictim())
11260 targets.remove(getVictim());
11262 // remove not LoS targets
11263 for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end();)
11265 if(!IsWithinLOSInMap(*tIter))
11267 std::list<Unit *>::iterator tIter2 = tIter;
11268 ++tIter;
11269 targets.erase(tIter2);
11271 else
11272 ++tIter;
11275 // no appropriate targets
11276 if(targets.empty())
11277 return NULL;
11279 // select random
11280 uint32 rIdx = urand(0,targets.size()-1);
11281 std::list<Unit *>::const_iterator tcIter = targets.begin();
11282 for(uint32 i = 0; i < rIdx; ++i)
11283 ++tcIter;
11285 return *tcIter;
11288 bool Unit::hasNegativeAuraWithInterruptFlag(uint32 flag)
11290 for (AuraMap::const_iterator iter = m_Auras.begin(); iter != m_Auras.end(); ++iter)
11292 if (!iter->second->IsPositive() && iter->second->GetSpellProto()->AuraInterruptFlags & flag)
11293 return true;
11295 return false;
11298 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply )
11300 if(val > 0)
11302 ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply);
11303 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,val,!apply);
11305 else
11307 ApplyPercentModFloatVar(m_modAttackSpeedPct[att], -val, apply);
11308 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME+att,-val,apply);
11312 void Unit::ApplyCastTimePercentMod(float val, bool apply )
11314 if(val > 0)
11315 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,val,!apply);
11316 else
11317 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED,-val,apply);
11320 uint32 Unit::GetCastingTimeForBonus( SpellEntry const *spellProto, DamageEffectType damagetype, uint32 CastingTime )
11322 // Not apply this to creature casted spells with casttime==0
11323 if(CastingTime==0 && GetTypeId()==TYPEID_UNIT && !((Creature*)this)->isPet())
11324 return 3500;
11326 if (CastingTime > 7000) CastingTime = 7000;
11327 if (CastingTime < 1500) CastingTime = 1500;
11329 if(damagetype == DOT && !IsChanneledSpell(spellProto))
11330 CastingTime = 3500;
11332 int32 overTime = 0;
11333 uint8 effects = 0;
11334 bool DirectDamage = false;
11335 bool AreaEffect = false;
11337 for ( uint32 i=0; i<3;++i)
11339 switch ( spellProto->Effect[i] )
11341 case SPELL_EFFECT_SCHOOL_DAMAGE:
11342 case SPELL_EFFECT_POWER_DRAIN:
11343 case SPELL_EFFECT_HEALTH_LEECH:
11344 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE:
11345 case SPELL_EFFECT_POWER_BURN:
11346 case SPELL_EFFECT_HEAL:
11347 DirectDamage = true;
11348 break;
11349 case SPELL_EFFECT_APPLY_AURA:
11350 switch ( spellProto->EffectApplyAuraName[i] )
11352 case SPELL_AURA_PERIODIC_DAMAGE:
11353 case SPELL_AURA_PERIODIC_HEAL:
11354 case SPELL_AURA_PERIODIC_LEECH:
11355 if ( GetSpellDuration(spellProto) )
11356 overTime = GetSpellDuration(spellProto);
11357 break;
11358 default:
11359 // -5% per additional effect
11360 ++effects;
11361 break;
11363 default:
11364 break;
11367 if(IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetA[i])) || IsAreaEffectTarget(Targets(spellProto->EffectImplicitTargetB[i])))
11368 AreaEffect = true;
11371 // Combined Spells with Both Over Time and Direct Damage
11372 if ( overTime > 0 && CastingTime > 0 && DirectDamage )
11374 // mainly for DoTs which are 3500 here otherwise
11375 uint32 OriginalCastTime = GetSpellCastTime(spellProto);
11376 if (OriginalCastTime > 7000) OriginalCastTime = 7000;
11377 if (OriginalCastTime < 1500) OriginalCastTime = 1500;
11378 // Portion to Over Time
11379 float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f));
11381 if ( damagetype == DOT )
11382 CastingTime = uint32(CastingTime * PtOT);
11383 else if ( PtOT < 1.0f )
11384 CastingTime = uint32(CastingTime * (1 - PtOT));
11385 else
11386 CastingTime = 0;
11389 // Area Effect Spells receive only half of bonus
11390 if ( AreaEffect )
11391 CastingTime /= 2;
11393 // -5% of total per any additional effect
11394 for ( uint8 i=0; i<effects; ++i)
11396 if ( CastingTime > 175 )
11398 CastingTime -= 175;
11400 else
11402 CastingTime = 0;
11403 break;
11407 return CastingTime;
11410 void Unit::UpdateAuraForGroup(uint8 slot)
11412 if(GetTypeId() == TYPEID_PLAYER)
11414 Player* player = (Player*)this;
11415 if(player->GetGroup())
11417 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
11418 player->SetAuraUpdateMask(slot);
11421 else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
11423 Pet *pet = ((Pet*)this);
11424 if(pet->isControlled())
11426 Unit *owner = GetOwner();
11427 if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
11429 ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS);
11430 pet->SetAuraUpdateMask(slot);
11436 float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
11438 if (!normalized || GetTypeId() != TYPEID_PLAYER)
11439 return float(GetAttackTime(attType))/1000.0f;
11441 Item *Weapon = ((Player*)this)->GetWeaponForAttack(attType);
11442 if (!Weapon)
11443 return 2.4; // fist attack
11445 switch (Weapon->GetProto()->InventoryType)
11447 case INVTYPE_2HWEAPON:
11448 return 3.3;
11449 case INVTYPE_RANGED:
11450 case INVTYPE_RANGEDRIGHT:
11451 case INVTYPE_THROWN:
11452 return 2.8;
11453 case INVTYPE_WEAPON:
11454 case INVTYPE_WEAPONMAINHAND:
11455 case INVTYPE_WEAPONOFFHAND:
11456 default:
11457 return Weapon->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_DAGGER ? 1.7 : 2.4;
11461 Aura* Unit::GetDummyAura( uint32 spell_id ) const
11463 Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
11464 for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
11465 if ((*itr)->GetId() == spell_id)
11466 return *itr;
11468 return NULL;
11471 bool Unit::IsUnderLastManaUseEffect() const
11473 return getMSTimeDiff(m_lastManaUse,getMSTime()) < 5000;
11476 void Unit::SetContestedPvP(Player *attackedPlayer)
11478 Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
11480 if(!player || attackedPlayer && (attackedPlayer == player || player->duel && player->duel->opponent == attackedPlayer))
11481 return;
11483 player->SetContestedPvPTimer(30000);
11484 if(!player->hasUnitState(UNIT_STAT_ATTACK_PLAYER))
11486 player->addUnitState(UNIT_STAT_ATTACK_PLAYER);
11487 player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP);
11488 // call MoveInLineOfSight for nearby contested guards
11489 SetVisibility(GetVisibility());
11491 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER))
11493 addUnitState(UNIT_STAT_ATTACK_PLAYER);
11494 // call MoveInLineOfSight for nearby contested guards
11495 SetVisibility(GetVisibility());
11499 void Unit::AddPetAura(PetAura const* petSpell)
11501 m_petAuras.insert(petSpell);
11502 if(Pet* pet = GetPet())
11503 pet->CastPetAura(petSpell);
11506 void Unit::RemovePetAura(PetAura const* petSpell)
11508 m_petAuras.erase(petSpell);
11509 if(Pet* pet = GetPet())
11510 pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
11513 Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
11515 Pet* pet = new Pet(HUNTER_PET);
11517 if(!pet->CreateBaseAtCreature(creatureTarget))
11519 delete pet;
11520 return NULL;
11523 pet->SetOwnerGUID(GetGUID());
11524 pet->SetCreatorGUID(GetGUID());
11525 pet->setFaction(getFaction());
11526 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, spell_id);
11528 if(GetTypeId()==TYPEID_PLAYER)
11529 pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
11531 if(IsPvP())
11532 pet->SetPvP(true);
11534 uint32 level = (creatureTarget->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget->getLevel();
11536 if(!pet->InitStatsForLevel(level))
11538 sLog.outError("Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget->GetEntry());
11539 delete pet;
11540 return NULL;
11543 pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
11544 // this enables pet details window (Shift+P)
11545 pet->AIM_Initialize();
11546 pet->InitPetCreateSpells();
11547 pet->InitLevelupSpellsForLevel();
11548 pet->InitTalentForLevel();
11549 pet->SetHealth(pet->GetMaxHealth());
11551 return pet;
11554 bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent )
11556 SpellEntry const* spellProto = aura->GetSpellProto ();
11558 // Get proc Event Entry
11559 spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
11561 // Aura info stored here
11562 Modifier *mod = aura->GetModifier();
11563 // Skip this auras
11564 if (isNonTriggerAura[mod->m_auraname])
11565 return false;
11566 // If not trigger by default and spellProcEvent==NULL - skip
11567 if (!isTriggerAura[mod->m_auraname] && spellProcEvent==NULL)
11568 return false;
11570 // Get EventProcFlag
11571 uint32 EventProcFlag;
11572 if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
11573 EventProcFlag = spellProcEvent->procFlags;
11574 else
11575 EventProcFlag = spellProto->procFlags; // else get from spell proto
11576 // Continue if no trigger exist
11577 if (!EventProcFlag)
11578 return false;
11580 // Check spellProcEvent data requirements
11581 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
11582 return false;
11584 // In most cases req get honor or XP from kill
11585 if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
11587 bool allow = ((Player*)this)->isHonorOrXPTarget(pVictim);
11588 // Shadow Word: Death - can trigger from every kill
11589 if (aura->GetId() == 32409)
11590 allow = true;
11591 if (!allow)
11592 return false;
11594 // Aura added by spell can`t trogger from self (prevent drop charges/do triggers)
11595 // But except periodic triggers (can triggered from self)
11596 if(procSpell && procSpell->Id == spellProto->Id && !(spellProto->procFlags&PROC_FLAG_ON_TAKE_PERIODIC))
11597 return false;
11599 // Check if current equipment allows aura to proc
11600 if(!isVictim && GetTypeId() == TYPEID_PLAYER)
11602 if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
11604 Item *item = NULL;
11605 if(attType == BASE_ATTACK)
11606 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
11607 else if (attType == OFF_ATTACK)
11608 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
11609 else
11610 item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
11612 if (!((Player*)this)->IsUseEquipedWeapon(attType==BASE_ATTACK))
11613 return false;
11615 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
11616 return false;
11618 else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
11620 // Check if player is wearing shield
11621 Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
11622 if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
11623 return false;
11626 // Get chance from spell
11627 float chance = (float)spellProto->procChance;
11628 // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
11629 if(spellProcEvent && spellProcEvent->customChance)
11630 chance = spellProcEvent->customChance;
11631 // If PPM exist calculate chance from PPM
11632 if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
11634 uint32 WeaponSpeed = GetAttackTime(attType);
11635 chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
11637 // Apply chance modifer aura
11638 if(Player* modOwner = GetSpellModOwner())
11639 modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
11641 return roll_chance_f(chance);
11644 bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
11646 // aura can be deleted at casts
11647 SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
11648 uint32 effIdx = triggeredByAura->GetEffIndex();
11649 int32 heal = triggeredByAura->GetModifier()->m_amount;
11650 uint64 caster_guid = triggeredByAura->GetCasterGUID();
11652 // jumps
11653 int32 jumps = triggeredByAura->GetAuraCharges()-1;
11655 // current aura expire
11656 triggeredByAura->SetAuraCharges(1); // will removed at next charges decrease
11658 // next target selection
11659 if(jumps > 0 && GetTypeId()==TYPEID_PLAYER && IS_PLAYER_GUID(caster_guid))
11661 float radius;
11662 if (spellProto->EffectRadiusIndex[effIdx])
11663 radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellProto->EffectRadiusIndex[effIdx]));
11664 else
11665 radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spellProto->rangeIndex));
11667 if(Player* caster = ((Player*)triggeredByAura->GetCaster()))
11669 caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL);
11671 if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius))
11673 // aura will applied from caster, but spell casted from current aura holder
11674 SpellModifier *mod = new SpellModifier;
11675 mod->op = SPELLMOD_CHARGES;
11676 mod->value = jumps-5; // negative
11677 mod->type = SPELLMOD_FLAT;
11678 mod->spellId = spellProto->Id;
11679 mod->mask = spellProto->SpellFamilyFlags;
11680 mod->mask2 = spellProto->SpellFamilyFlags2;
11682 caster->AddSpellMod(mod, true);
11683 CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID());
11684 caster->AddSpellMod(mod, false);
11689 // heal
11690 CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid);
11691 return true;
11694 void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo)
11696 uint64 target_guid = GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT);
11698 if(!IS_UNIT_GUID(target_guid))
11699 return;
11701 Unit* target = ObjectAccessor::GetUnit(*this, target_guid);
11702 if(!target)
11703 return;
11705 for (AuraMap::iterator iter = target->GetAuras().begin(); iter != target->GetAuras().end(); )
11707 if (iter->second->GetId() == spellInfo->Id && iter->second->GetCasterGUID()==GetGUID())
11708 target->RemoveAura(iter);
11709 else
11710 ++iter;
11714 void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
11716 WorldObject::SetPhaseMask(newPhaseMask,update);
11718 if(IsInWorld())
11719 if(Pet* pet = GetPet())
11720 pet->SetPhaseMask(newPhaseMask,true);
11723 void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool casting /*= false*/ )
11725 if(GetTypeId() == TYPEID_PLAYER)
11726 ((Player*)this)->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0));
11727 else
11729 GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation);
11731 WorldPacket data;
11732 // Work strange for many spells: triggered active mover set for targeted player to creature
11733 //BuildTeleportAckMsg(&data, x, y, z, orientation);
11734 BuildHeartBeatMsg(&data);
11735 SendMessageToSet(&data, false);
11739 void Unit::SetPvP( bool state )
11741 if(state)
11742 SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
11743 else
11744 RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
11746 if(Pet* pet = GetPet())
11747 pet->SetPvP(state);
11748 if(Unit* charmed = GetCharm())
11749 charmed->SetPvP(state);
11751 for (int8 i = 0; i < MAX_TOTEM; ++i)
11752 if(m_TotemSlot[i])
11753 if(Creature *totem = GetMap()->GetCreature(m_TotemSlot[i]))
11754 totem->SetPvP(state);