2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
49 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
53 1.25f
, // MOVE_RUN_BACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIM_BACK
56 3.141594f
, // MOVE_TURN_RATE
58 4.5f
, // MOVE_FLIGHT_BACK
61 // auraTypes contains attacker auras capable of proc'ing cast auras
62 static Unit::AuraTypeSet
GenerateAttakerProcCastAuraTypes()
64 static Unit::AuraTypeSet auraTypes
;
65 auraTypes
.insert(SPELL_AURA_DUMMY
);
66 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
67 auraTypes
.insert(SPELL_AURA_MOD_HASTE
);
68 auraTypes
.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
72 // auraTypes contains victim auras capable of proc'ing cast auras
73 static Unit::AuraTypeSet
GenerateVictimProcCastAuraTypes()
75 static Unit::AuraTypeSet auraTypes
;
76 auraTypes
.insert(SPELL_AURA_DUMMY
);
77 auraTypes
.insert(SPELL_AURA_PRAYER_OF_MENDING
);
78 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
82 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
83 static Unit::AuraTypeSet
GenerateAttakerProcEffectAuraTypes()
85 static Unit::AuraTypeSet auraTypes
;
86 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_DONE
);
87 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
88 auraTypes
.insert(SPELL_AURA_MOD_CASTING_SPEED
);
89 auraTypes
.insert(SPELL_AURA_MOD_RATING
);
93 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
94 static Unit::AuraTypeSet
GenerateVictimProcEffectAuraTypes()
96 static Unit::AuraTypeSet auraTypes
;
97 auraTypes
.insert(SPELL_AURA_MOD_RESISTANCE
);
98 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
99 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
100 auraTypes
.insert(SPELL_AURA_MOD_BLOCK_PERCENT
);
101 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
105 static Unit::AuraTypeSet attackerProcCastAuraTypes
= GenerateAttakerProcCastAuraTypes();
106 static Unit::AuraTypeSet attackerProcEffectAuraTypes
= GenerateAttakerProcEffectAuraTypes();
108 static Unit::AuraTypeSet victimProcCastAuraTypes
= GenerateVictimProcCastAuraTypes();
109 static Unit::AuraTypeSet victimProcEffectAuraTypes
= GenerateVictimProcEffectAuraTypes();
111 // auraTypes contains auras capable of proc'ing for attacker and victim
112 static Unit::AuraTypeSet
GenerateProcAuraTypes()
114 Unit::AuraTypeSet auraTypes
;
115 auraTypes
.insert(attackerProcCastAuraTypes
.begin(),attackerProcCastAuraTypes
.end());
116 auraTypes
.insert(attackerProcEffectAuraTypes
.begin(),attackerProcEffectAuraTypes
.end());
117 auraTypes
.insert(victimProcCastAuraTypes
.begin(),victimProcCastAuraTypes
.end());
118 auraTypes
.insert(victimProcEffectAuraTypes
.begin(),victimProcEffectAuraTypes
.end());
122 static Unit::AuraTypeSet procAuraTypes
= GenerateProcAuraTypes();
124 bool IsPassiveStackableSpell( uint32 spellId
)
126 if(!IsPassiveSpell(spellId
))
129 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
133 for(int j
= 0; j
< 3; ++j
)
135 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
143 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
145 m_objectType
|= TYPEMASK_UNIT
;
146 m_objectTypeId
= TYPEID_UNIT
;
148 m_updateFlag
= (UPDATEFLAG_HIGHGUID
| UPDATEFLAG_LIVING
| UPDATEFLAG_HASPOSITION
);
150 m_attackTimer
[BASE_ATTACK
] = 0;
151 m_attackTimer
[OFF_ATTACK
] = 0;
152 m_attackTimer
[RANGED_ATTACK
] = 0;
153 m_modAttackSpeedPct
[BASE_ATTACK
] = 1.0f
;
154 m_modAttackSpeedPct
[OFF_ATTACK
] = 1.0f
;
155 m_modAttackSpeedPct
[RANGED_ATTACK
] = 1.0f
;
161 m_deathState
= ALIVE
;
163 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
164 m_currentSpells
[i
] = NULL
;
168 for(int i
= 0; i
< MAX_TOTEM
; ++i
)
171 m_ObjectSlot
[0] = m_ObjectSlot
[1] = m_ObjectSlot
[2] = m_ObjectSlot
[3] = 0;
173 //m_AurasCheck = 2000;
174 //m_removeAuraTimer = 4;
178 m_Visibility
= VISIBILITY_ON
;
180 m_detectInvisibilityMask
= 0;
181 m_invisibilityMask
= 0;
183 m_ShapeShiftFormSpellId
= 0;
184 m_canModifyStats
= false;
186 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
187 m_spellImmune
[i
].clear();
188 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
190 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
191 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
192 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
193 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
195 // implement 50% base damage from offhand
196 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
198 for (int i
= 0; i
< 3; i
++)
200 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
201 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
203 for (int i
= 0; i
< MAX_STATS
; i
++)
204 m_createStats
[i
] = 0.0f
;
207 m_modMeleeHitChance
= 0.0f
;
208 m_modRangedHitChance
= 0.0f
;
209 m_modSpellHitChance
= 0.0f
;
210 m_baseSpellCritChance
= 5;
215 //m_victimThreat = 0.0f;
216 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
217 m_threatModifier
[i
] = 1.0f
;
219 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
220 m_speed_rate
[i
] = 1.0f
;
224 m_unit_movement_flags
= 0;
226 // remove aurastates allowing special moves
227 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
228 m_reactiveTimer
[i
] = 0;
233 // set current spells as deletable
234 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
236 if (m_currentSpells
[i
])
238 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
239 m_currentSpells
[i
] = NULL
;
243 RemoveAllGameObjects();
244 RemoveAllDynObjects();
246 if(m_charmInfo
) delete m_charmInfo
;
249 void Unit::Update( uint32 p_time
)
251 /*if(p_time > m_AurasCheck)
256 m_AurasCheck -= p_time;*/
258 // WARNING! Order of execution here is important, do not change.
259 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
260 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
261 m_Events
.Update( p_time
);
262 _UpdateSpells( p_time
);
264 // update combat timer only for players and pets
265 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
267 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
268 // targets without stopping half way there and running off.
269 // These flags are reset after target dies or another command is given.
270 if( m_HostilRefManager
.isEmpty() )
272 // m_CombatTimer set at aura start and it will be freeze until aura removing
273 if ( m_CombatTimer
<= p_time
)
276 m_CombatTimer
-= p_time
;
280 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
282 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
285 // update abilities available only for fraction of time
286 UpdateReactives( p_time
);
288 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, GetHealth() < GetMaxHealth()*0.20f
);
289 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, GetHealth() < GetMaxHealth()*0.35f
);
291 i_motionMaster
.UpdateMotion(p_time
);
294 bool Unit::haveOffhandWeapon() const
296 if(GetTypeId() == TYPEID_PLAYER
)
297 return ((Player
*)this)->GetWeaponForAttack(OFF_ATTACK
,true);
302 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player
* player
)
305 if(GetMotionMaster()->GetDestination(x
, y
, z
))
306 SendMonsterMoveWithSpeed(x
, y
, z
, GetUnitMovementFlags(), 0, player
);
309 void Unit::SendMonsterMoveWithSpeed(float x
, float y
, float z
, uint32 MovementFlags
, uint32 transitTime
, Player
* player
)
313 float dx
= x
- GetPositionX();
314 float dy
= y
- GetPositionY();
315 float dz
= z
- GetPositionZ();
317 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
323 double speed
= GetSpeed((MovementFlags
& MOVEMENTFLAG_WALK_MODE
) ? MOVE_WALK
: MOVE_RUN
);
327 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
329 //float orientation = (float)atan2((double)dy, (double)dx);
330 SendMonsterMove(x
, y
, z
, 0, MovementFlags
, transitTime
, player
);
333 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, uint32 MovementFlags
, uint32 Time
, Player
* player
)
335 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
336 data
.append(GetPackGUID());
338 // Point A, starting location
339 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
340 // unknown field - unrelated to orientation
341 // seems to increment about 1000 for every 1.7 seconds
342 // for now, we'll just use mstime
345 data
<< uint8(type
); // unknown
348 case 0: // normal packet
350 case 1: // stop packet
351 SendMessageToSet( &data
, true );
353 case 2: // not used currently
358 case 3: // not used currently
359 data
<< uint64(0); // probably target guid
361 case 4: // not used currently
362 data
<< float(0); // probably orientation
366 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
367 data
<< uint32(MovementFlags
);
369 data
<< Time
; // Time in between points
370 data
<< uint32(1); // 1 single waypoint
371 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
374 player
->GetSession()->SendPacket(&data
);
376 SendMessageToSet( &data
, true );
379 void Unit::SendMonsterMoveByPath(Path
const& path
, uint32 start
, uint32 end
, uint32 MovementFlags
)
381 uint32 traveltime
= uint32(path
.GetTotalLength(start
, end
) * 32);
383 uint32 pathSize
= end
-start
;
385 WorldPacket
data( SMSG_MONSTER_MOVE
, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize
*4*3) );
386 data
.append(GetPackGUID());
387 data
<< GetPositionX();
388 data
<< GetPositionY();
389 data
<< GetPositionZ();
391 // unknown field - unrelated to orientation
392 // seems to increment about 1000 for every 1.7 seconds
393 // for now, we'll just use mstime
397 data
<< uint32( MovementFlags
);
398 data
<< uint32( traveltime
);
399 data
<< uint32( pathSize
);
400 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
402 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
403 SendMessageToSet(&data
, true);
406 void Unit::resetAttackTimer(WeaponAttackType type
)
408 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
411 bool Unit::canReachWithAttack(Unit
*pVictim
) const
414 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
417 return IsWithinDistInMap(pVictim
, reach
);
420 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
422 if (auraType
>= TOTAL_AURAS
) return;
423 AuraList::iterator iter
, next
;
424 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
431 RemoveAurasDueToSpell((*iter
)->GetId());
432 if (!m_modAuras
[auraType
].empty())
433 next
= m_modAuras
[auraType
].begin();
440 bool Unit::HasAuraType(AuraType auraType
) const
442 return (!m_modAuras
[auraType
].empty());
445 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
446 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
448 if(!HasAuraType(auraType
))
451 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
452 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
453 float chance
= float(damage
) / max_dmg
* 100.0f
;
454 if (roll_chance_f(chance
))
455 RemoveSpellsCausingAura(auraType
);
458 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
460 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
463 //You don't lose health from damage taken from another player while in a sanctuary
464 //You still see it in the combat log though
465 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
467 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
468 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
472 // remove affects from victim (including from 0 damage and DoTs)
474 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
476 // remove affects from attacker at any non-DoT damage (including 0 damage)
477 if( damagetype
!= DOT
)
479 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
480 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
483 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
485 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
486 pVictim
->SetStandState(PLAYER_STATE_NONE
);
489 //Script Event damage Deal
490 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
491 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
492 //Script Event damage taken
493 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
494 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
498 // Rage from physical damage received .
499 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
500 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
505 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
506 // root type spells do not dispel the root effect
507 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
508 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
510 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
512 // no xp,health if type 8 /critters/
513 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
515 pVictim
->setDeathState(JUST_DIED
);
516 pVictim
->SetHealth(0);
518 // allow loot only if has loot_id in creature_template
519 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
520 if(cInfo
&& cInfo
->lootid
)
521 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
523 // some critters required for quests
524 if(GetTypeId() == TYPEID_PLAYER
)
525 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
530 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
531 ((Creature
*)pVictim
)->AI()->AttackStart(this);
534 DEBUG_LOG("DealDamageStart");
536 uint32 health
= pVictim
->GetHealth();
537 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
539 // duel ends when player has 1 or less hp
540 bool duel_hasEnded
= false;
541 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
543 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
544 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
547 duel_hasEnded
= true;
550 if(pVictim
!= this && damagetype
!= DOT
)
552 SetInCombatWith(pVictim
);
553 pVictim
->SetInCombatWith(this);
555 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
556 SetContestedPvP(attackedPlayer
);
559 // Rage from Damage made (only from direct weapon damage)
560 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
562 uint32 weaponSpeedHitFactor
;
564 switch(cleanDamage
->attackType
)
568 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
569 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
571 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
573 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
579 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
580 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
582 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
584 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
593 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
595 if(((Player
*)pVictim
)->InBattleGround())
597 Player
*killer
= ((Player
*)this);
598 if(killer
!= ((Player
*)pVictim
))
599 if(BattleGround
*bg
= killer
->GetBattleGround())
600 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
604 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
605 ((Creature
*)pVictim
)->SetLootRecipient(this);
606 if (health
<= damage
)
608 DEBUG_LOG("DealDamage: victim just died");
610 // find player: owner of controlled `this` or `this` itself maybe
611 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
613 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
614 player
= ((Creature
*)pVictim
)->GetLootRecipient();
615 // Reward player, his pets, and group/raid members
616 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
617 if(player
&& player
!=pVictim
)
618 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
619 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
621 DEBUG_LOG("DealDamageAttackStop");
624 pVictim
->CombatStop();
625 pVictim
->getHostilRefManager().deleteReferences();
627 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
629 // if talent known but not triggered (check priest class for speedup check)
630 Aura
* spiritOfRedemtionTalentReady
= NULL
;
631 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
632 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
634 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
635 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
637 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
639 spiritOfRedemtionTalentReady
= *itr
;
645 DEBUG_LOG("SET JUST_DIED");
646 if(!spiritOfRedemtionTalentReady
)
647 pVictim
->setDeathState(JUST_DIED
);
649 DEBUG_LOG("DealDamageHealth1");
651 if(spiritOfRedemtionTalentReady
)
653 // save value before aura remove
654 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
656 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
658 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
659 pVictim
->RemoveAllAurasOnDeath();
661 // restore for use at real death
662 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
664 // FORM_SPIRITOFREDEMPTION and related auras
665 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
668 pVictim
->SetHealth(0);
670 // remember victim PvP death for corpse type and corpse reclaim delay
671 // at original death (not at SpiritOfRedemtionTalent timeout)
672 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
673 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
675 // Call KilledUnit for creatures
676 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
677 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
679 // 10% durability loss on death
680 // clean InHateListOf
681 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
683 // only if not player and not controlled by player pet. And not at BG
684 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
686 DEBUG_LOG("We are dead, loosing 10 percents durability");
687 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
688 // durability lost message
689 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
690 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
693 else // creature died
695 DEBUG_LOG("DealDamageNotPlayer");
696 Creature
*cVictim
= (Creature
*)pVictim
;
698 if(!cVictim
->isPet())
700 cVictim
->DeleteThreatList();
701 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
703 // Call creature just died function
705 cVictim
->AI()->JustDied(this);
707 // Dungeon specific stuff, only applies to players killing creatures
708 if(cVictim
->GetInstanceId())
710 Map
*m
= cVictim
->GetMap();
711 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
712 // TODO: do instance binding anyway if the charmer/owner is offline
714 if(m
->IsDungeon() && creditedPlayer
)
716 if(m
->IsRaid() || m
->IsHeroic())
718 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
719 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
723 // the reset time is set but not added to the scheduler
724 // until the players leave the instance
725 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
726 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
727 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
733 // last damage from non duel opponent or opponent controlled creature
736 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
737 Player
*he
= (Player
*)pVictim
;
741 he
->duel
->opponent
->CombatStopWithPets(true);
742 he
->CombatStopWithPets(true);
744 he
->DuelComplete(DUEL_INTERUPTED
);
747 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
748 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->InBattleGround())
750 Player
*killed
= ((Player
*)pVictim
);
751 if(BattleGround
*bg
= killed
->GetBattleGround())
753 bg
->HandleKillPlayer(killed
, player
);
754 //later we can add support for creature->player kills here i'm
755 //not sure, but i guess those kills also get counted in av
756 //else if(GetTypeId() == TYPEID_UNIT)
757 // bg->HandleKillPlayer(killed,(Creature*)this);
760 else // if (health <= damage)
762 DEBUG_LOG("DealDamageAlive");
764 pVictim
->ModifyHealth(- (int32
)damage
);
766 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
767 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
769 uint32 procVictim
= PROC_FLAG_NONE
;
771 // if just dropped below 20% (for CheatDeath)
772 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
773 procVictim
= PROC_FLAG_LOW_HEALTH
;
775 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
778 if(damagetype
!= DOT
)
782 // if have target and damage pVictim just call AI reaction
783 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
784 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
788 // if not have main target then attack state with target (including AI call)
789 //start melee attacks only after melee hit
790 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
794 // polymorphed and other negative transformed cases
795 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
796 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
798 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
799 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
801 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
803 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
804 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
806 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
808 else // victim is a player
810 // Rage from damage received
811 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
813 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
814 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
817 // random durability for items (HIT TAKEN)
818 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
820 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
821 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
825 if(GetTypeId()==TYPEID_PLAYER
)
827 // random durability for items (HIT DONE)
828 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
830 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
831 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
835 // TODO: Store auras by interrupt flag to speed this up.
836 AuraMap
& vAuras
= pVictim
->GetAuras();
837 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
839 const SpellEntry
*se
= i
->second
->GetSpellProto();
841 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
844 if (se
->procFlags
& (1<<3))
846 if (!roll_chance_i(se
->procChance
))
851 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
852 // FIXME: this may cause the auras with proc chance to be rerolled several times
853 next
= vAuras
.begin();
858 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
860 if( damagetype
!= DOT
)
862 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
864 // skip channeled spell (processed differently below)
865 if (i
== CURRENT_CHANNELED_SPELL
)
868 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
869 if(spell
->getState() == SPELL_STATE_PREPARING
)
874 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
876 if (spell
->getState() == SPELL_STATE_CASTING
)
878 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
879 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
881 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
882 spell
->DelayedChannel();
884 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
886 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
887 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
890 else if (spell
->getState() == SPELL_STATE_DELAYED
)
891 // break channeled spell in delayed state on damage
893 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
894 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
899 // last damage from duel opponent
902 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
903 Player
*he
= (Player
*)pVictim
;
909 he
->duel
->opponent
->CombatStopWithPets(true);
910 he
->CombatStopWithPets(true);
912 he
->CastSpell(he
, 7267, true); // beg
913 he
->DuelComplete(DUEL_WON
);
917 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
922 void Unit::CastStop(uint32 except_spellid
)
924 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
925 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
926 InterruptSpell(i
,false);
929 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
931 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
935 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
939 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
942 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
946 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
951 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
953 if(!originalCaster
&& triggeredByAura
)
954 originalCaster
= triggeredByAura
->GetCasterGUID();
956 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
958 SpellCastTargets targets
;
959 targets
.setUnitTarget( Victim
);
960 spell
->m_CastItem
= castItem
;
961 spell
->prepare(&targets
, triggeredByAura
);
964 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
966 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
970 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
974 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggeredByAura
, originalCaster
);
977 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
)
981 sLog
.outError("CastCustomSpell: unknown spell");
986 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
988 if(!originalCaster
&& triggeredByAura
)
989 originalCaster
= triggeredByAura
->GetCasterGUID();
991 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
994 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
997 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1000 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1002 SpellCastTargets targets
;
1003 targets
.setUnitTarget( Victim
);
1004 spell
->m_CastItem
= castItem
;
1005 spell
->prepare(&targets
, triggeredByAura
);
1008 // used for scripting
1009 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1011 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1015 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()));
1019 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
1022 // used for scripting
1023 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1027 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1032 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1034 if(!originalCaster
&& triggeredByAura
)
1035 originalCaster
= triggeredByAura
->GetCasterGUID();
1037 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1039 SpellCastTargets targets
;
1040 targets
.setDestination(x
, y
, z
);
1041 spell
->m_CastItem
= castItem
;
1042 spell
->prepare(&targets
, triggeredByAura
);
1045 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1047 // TODO this in only generic way, check for exceptions
1048 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1050 // Per-damage class calculation
1051 switch (spellInfo
->DmgClass
)
1053 // Melee and Ranged Spells
1054 case SPELL_DAMAGE_CLASS_RANGED
:
1055 case SPELL_DAMAGE_CLASS_MELEE
:
1057 // Calculate physical outcome
1058 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1060 //Used to store the Hit Outcome
1061 cleanDamage
->hitOutCome
= outcome
;
1063 // Return miss/evade first (sends miss message)
1066 case MELEE_HIT_EVADE
:
1068 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1072 case MELEE_HIT_MISS
:
1074 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1077 if(GetTypeId()== TYPEID_PLAYER
)
1078 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1080 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1085 // Hitinfo, Victimstate
1086 uint32 hitInfo
= HITINFO_NORMALSWING
;
1087 VictimState victimState
= VICTIMSTATE_NORMAL
;
1090 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1092 // apply spellmod to Done damage
1093 if(Player
* modOwner
= GetSpellModOwner())
1094 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1096 //Calculate armor mitigation
1097 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1099 // random durability for main hand weapon (ABSORB)
1100 if(damageAfterArmor
< *damage
)
1101 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1102 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1103 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1105 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1106 *damage
= damageAfterArmor
;
1111 // Calculate damage bonus
1112 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1118 case MELEE_HIT_BLOCK_CRIT
:
1119 case MELEE_HIT_CRIT
:
1121 uint32 bonusDmg
= *damage
;
1123 // Apply crit_damage bonus
1124 if(Player
* modOwner
= GetSpellModOwner())
1125 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1127 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1128 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1129 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1130 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1131 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1133 *damage
+= bonusDmg
;
1135 // Resilience - reduce crit damage
1136 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1138 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1139 cleanDamage
->damage
+= resilienceReduction
;
1140 *damage
-= resilienceReduction
;
1144 hitInfo
|= HITINFO_CRITICALHIT
;
1146 ModifyAuraState(AURA_STATE_CRIT
, true);
1147 StartReactiveTimer( REACTIVE_CRIT
);
1149 if(getClass()==CLASS_HUNTER
)
1151 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1152 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1155 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1157 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1158 if (blocked_amount
>= *damage
)
1160 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1161 victimState
= VICTIMSTATE_BLOCKS
;
1162 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1167 // To Help Calculate Rage
1168 cleanDamage
->damage
+= blocked_amount
;
1169 *damage
= *damage
- blocked_amount
;
1172 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1173 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1175 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1178 ((Player
*)pVictim
)->UpdateDefense();
1180 // random durability for main hand weapon (BLOCK)
1181 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1182 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1187 case MELEE_HIT_PARRY
:
1189 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1191 victimState
= VICTIMSTATE_PARRY
;
1193 // Counter-attack ( explained in Unit::DoAttackDamage() )
1194 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1196 // Get attack timers
1197 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1198 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1200 // Reduce attack time
1201 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1203 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1204 float percent60
= 3 * percent20
;
1205 if(offtime
> percent20
&& offtime
<= percent60
)
1207 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1209 else if(offtime
> percent60
)
1211 offtime
-= 2 * percent20
;
1212 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1217 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1218 float percent60
= 3 * percent20
;
1219 if(basetime
> percent20
&& basetime
<= percent60
)
1221 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1223 else if(basetime
> percent60
)
1225 basetime
-= 2 * percent20
;
1226 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1231 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1233 // Update victim defense ?
1234 ((Player
*)pVictim
)->UpdateDefense();
1236 // random durability for main hand weapon (PARRY)
1237 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1238 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1242 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1244 // Mongoose bite - set only Counterattack here
1245 if (pVictim
->getClass() == CLASS_HUNTER
)
1247 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1248 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1252 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1253 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1257 case MELEE_HIT_DODGE
:
1259 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1260 ((Player
*)pVictim
)->UpdateDefense();
1262 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1264 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1265 victimState
= VICTIMSTATE_DODGE
;
1268 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1271 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1273 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1274 StartReactiveTimer( REACTIVE_OVERPOWER
);
1278 if (pVictim
->getClass() != CLASS_ROGUE
)
1280 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1281 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1285 case MELEE_HIT_BLOCK
:
1287 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1288 if (blocked_amount
>= *damage
)
1290 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1291 victimState
= VICTIMSTATE_BLOCKS
;
1292 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1297 // To Help Calculate Rage
1298 cleanDamage
->damage
+= blocked_amount
;
1299 *damage
= *damage
- blocked_amount
;
1302 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1303 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1305 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1308 ((Player
*)pVictim
)->UpdateDefense();
1310 // random durability for main hand weapon (BLOCK)
1311 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1312 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1316 case MELEE_HIT_EVADE
: // already processed early
1317 case MELEE_HIT_MISS
: // already processed early
1318 case MELEE_HIT_GLANCING
:
1319 case MELEE_HIT_CRUSHING
:
1320 case MELEE_HIT_NORMAL
:
1324 // do all damage=0 cases here
1326 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1331 case SPELL_DAMAGE_CLASS_NONE
:
1332 case SPELL_DAMAGE_CLASS_MAGIC
:
1334 // Calculate damage bonus
1335 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1337 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1340 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1342 // Resilience - reduce crit damage
1343 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1345 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1346 if(*damage
> damage_reduction
)
1347 *damage
-= damage_reduction
;
1352 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1354 // spell proc all magic damage==0 case in this function
1358 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1359 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1361 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1368 // TODO this in only generic way, check for exceptions
1369 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1372 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1374 if(!this || !pVictim
)
1376 if(!isAlive() || !pVictim
->isAlive())
1379 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1383 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1387 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1389 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1392 // Calculate absorb & resists
1396 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1398 //No more damage left, target absorbed and/or resisted all damage
1399 if (damage
> absorb
+ resist
)
1400 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1403 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1406 HitInfo
|= HITINFO_ABSORB
;
1409 HitInfo
|= HITINFO_RESIST
;
1410 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1414 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1419 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1422 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1423 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1425 // Actual log sent to client
1426 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1429 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1430 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1434 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1435 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1438 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1444 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1447 if(cleanDamage
.damage
)
1448 // Rage from damage received.
1449 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1450 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1456 void Unit::HandleEmoteCommand(uint32 anim_id
)
1458 WorldPacket
data( SMSG_EMOTE
, 12 );
1459 data
<< uint32(anim_id
);
1460 data
<< uint64(GetGUID());
1461 SendMessageToSet(&data
, true);
1464 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1466 uint32 newdamage
= 0;
1467 float armor
= pVictim
->GetArmor();
1468 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1469 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1471 if (armor
<0.0f
) armor
=0.0f
;
1473 float tmpvalue
= 0.0f
;
1474 if(getLevel() <= 59) //Level 1-59
1475 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1476 else if(getLevel() < 70) //Level 60-69
1477 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1479 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1483 if(tmpvalue
> 0.75f
)
1485 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1487 return (newdamage
> 1) ? newdamage
: 1;
1490 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1492 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1495 // Magic damage, check for resists
1496 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1498 // Get base victim resistance for school
1499 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1500 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1501 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1503 tmpvalue2
*= (float)(0.15f
/ getLevel());
1504 if (tmpvalue2
< 0.0f
)
1506 if (tmpvalue2
> 0.75f
)
1508 uint32 ran
= urand(0, 100);
1509 uint32 faq
[4] = {24,6,4,6};
1512 for (uint8 i
= 0; i
< 4; i
++)
1514 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1520 if (damagetype
== DOT
&& m
== 4)
1521 *resist
+= uint32(damage
- 1);
1523 *resist
+= uint32(damage
* m
/ 4);
1524 if(*resist
> damage
)
1530 int32 RemainingDamage
= damage
- *resist
;
1532 // absorb without mana cost
1533 int32 reflectDamage
= 0;
1534 Aura
* reflectAura
= NULL
;
1535 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1536 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1540 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1544 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1546 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1548 if (pVictim
->GetHealth() <= RemainingDamage
)
1550 int32 chance
= (*i
)->GetModifier()->m_amount
;
1551 if (roll_chance_i(chance
))
1553 pVictim
->CastSpell(pVictim
,31231,true);
1554 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1556 // with health > 10% lost health until health==10%, in other case no losses
1557 uint32 health10
= pVictim
->GetMaxHealth()/10;
1558 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1564 int32 currentAbsorb
;
1567 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1569 if(Unit
* caster
= (*i
)->GetCaster())
1571 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1572 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1574 switch((*k
)->GetModifier()->m_miscvalue
)
1576 case 5065: // Rank 1
1577 case 5064: // Rank 2
1578 case 5063: // Rank 3
1579 case 5062: // Rank 4
1580 case 5061: // Rank 5
1582 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1583 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1585 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1598 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1600 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1601 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1602 next
= vSchoolAbsorb
.begin();
1606 currentAbsorb
= RemainingDamage
;
1607 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1610 RemainingDamage
-= currentAbsorb
;
1612 // do not cast spells while looping auras; auras can get invalid otherwise
1614 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1616 // absorb by mana cost
1617 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1618 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1622 // check damage school mask
1623 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1626 int32 currentAbsorb
;
1627 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1628 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1630 currentAbsorb
= RemainingDamage
;
1632 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1633 if(Player
*modOwner
= GetSpellModOwner())
1634 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1636 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1637 if (currentAbsorb
> maxAbsorb
)
1638 currentAbsorb
= maxAbsorb
;
1640 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1641 if((*i
)->GetModifier()->m_amount
<= 0)
1643 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1644 next
= vManaShield
.begin();
1647 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1648 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1650 RemainingDamage
-= currentAbsorb
;
1653 // only split damage if not damaging yourself
1656 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1657 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1661 // check damage school mask
1662 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1665 // Damage can be splitted only if aura has an alive caster
1666 Unit
*caster
= (*i
)->GetCaster();
1667 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1670 int32 currentAbsorb
;
1671 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1672 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1674 currentAbsorb
= RemainingDamage
;
1676 RemainingDamage
-= currentAbsorb
;
1678 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1680 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1681 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1684 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1685 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1689 // check damage school mask
1690 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1693 // Damage can be splitted only if aura has an alive caster
1694 Unit
*caster
= (*i
)->GetCaster();
1695 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1698 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1700 RemainingDamage
-= splitted
;
1702 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1704 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1705 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1709 *absorb
= damage
- RemainingDamage
- *resist
;
1712 void Unit::DoAttackDamage (Unit
*pVictim
, uint32
*damage
, CleanDamage
*cleanDamage
, uint32
*blocked_amount
, SpellSchoolMask damageSchoolMask
, uint32
*hitInfo
, VictimState
*victimState
, uint32
*absorbDamage
, uint32
*resistDamage
, WeaponAttackType attType
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
1714 MeleeHitOutcome outcome
;
1716 // If is casted Melee spell, calculate like physical
1718 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1720 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1722 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1723 pVictim
->AddThreat(this, 0.0f
);
1726 case MELEE_HIT_EVADE
:
1728 *hitInfo
|= HITINFO_MISS
;
1730 cleanDamage
->damage
= 0;
1733 case MELEE_HIT_MISS
:
1735 *hitInfo
|= HITINFO_MISS
;
1737 cleanDamage
->damage
= 0;
1738 if(GetTypeId()== TYPEID_PLAYER
)
1739 ((Player
*)this)->UpdateWeaponSkill(attType
);
1744 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1745 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1746 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1748 // -probability is between 0% and 40%
1750 float Probability
= 20;
1752 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1753 if( pVictim
->getLevel() < 30 )
1754 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1756 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1757 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1759 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1761 if(Probability
> 40.0f
)
1762 Probability
= 40.0f
;
1764 if(roll_chance_f(Probability
))
1765 CastSpell(pVictim
, 1604, true);
1768 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1769 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1771 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1773 // random durability for main hand weapon (ABSORB)
1774 if(damageAfterArmor
< *damage
)
1775 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1776 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1777 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1779 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1780 *damage
= damageAfterArmor
;
1783 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1784 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1786 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1787 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1791 case MELEE_HIT_BLOCK_CRIT
:
1792 case MELEE_HIT_CRIT
:
1796 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| 0x8;
1800 crit_bonus
= *damage
;
1802 // Apply crit_damage bonus for melee spells
1805 if(Player
* modOwner
= GetSpellModOwner())
1806 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1808 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1809 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1810 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1811 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1812 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1815 *damage
+= crit_bonus
;
1817 uint32 resilienceReduction
= 0;
1819 if(attType
== RANGED_ATTACK
)
1821 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1822 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1823 // Resilience - reduce crit damage
1824 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1825 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1829 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1830 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1831 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1832 // Resilience - reduce crit damage
1833 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1834 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1837 *damage
-= resilienceReduction
;
1838 cleanDamage
->damage
+= resilienceReduction
;
1840 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1841 ((Player
*)this)->UpdateWeaponSkill(attType
);
1843 ModifyAuraState(AURA_STATE_CRIT
, true);
1844 StartReactiveTimer( REACTIVE_CRIT
);
1846 if(getClass()==CLASS_HUNTER
)
1848 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1849 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1852 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1854 *blocked_amount
= pVictim
->GetShieldBlockValue();
1856 if (pVictim
->GetUnitBlockChance())
1857 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1859 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1861 //Only set VICTIMSTATE_BLOCK on a full block
1862 if (*blocked_amount
>= uint32(*damage
))
1864 *victimState
= VICTIMSTATE_BLOCKS
;
1865 *blocked_amount
= uint32(*damage
);
1868 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1871 ((Player
*)pVictim
)->UpdateDefense();
1873 // random durability for main hand weapon (BLOCK)
1874 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1875 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1878 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1879 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1883 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1886 case MELEE_HIT_PARRY
:
1888 if(attType
== RANGED_ATTACK
) //range attack - no parry
1890 outcome
= MELEE_HIT_NORMAL
;
1894 cleanDamage
->damage
+= *damage
;
1896 *victimState
= VICTIMSTATE_PARRY
;
1898 // instant (maybe with small delay) counter attack
1900 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1901 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1903 // after parry nearest next attack time will reduced at %40 from full attack time.
1904 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1905 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1907 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1908 float percent60
= 3*percent20
;
1909 // set to 20% if in range 20%...20+40% of full time
1910 if(offtime
> percent20
&& offtime
<= percent60
)
1912 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1914 // decrease at %40 from full time
1915 else if(offtime
> percent60
)
1917 offtime
-= 2*percent20
;
1918 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1924 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1925 float percent60
= 3*percent20
;
1926 // set to 20% if in range 20%...20+40% of full time
1927 if(basetime
> percent20
&& basetime
<= percent60
)
1929 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1931 // decrease at %40 from full time
1932 else if(basetime
> percent60
)
1934 basetime
-= 2*percent20
;
1935 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1941 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1943 // Update victim defense ?
1944 ((Player
*)pVictim
)->UpdateDefense();
1946 // random durability for main hand weapon (PARRY)
1947 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1948 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1951 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1953 if (pVictim
->getClass() == CLASS_HUNTER
)
1955 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1956 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1960 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1961 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1964 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1967 case MELEE_HIT_DODGE
:
1969 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1971 outcome
= MELEE_HIT_NORMAL
;
1975 cleanDamage
->damage
+= *damage
;
1977 *victimState
= VICTIMSTATE_DODGE
;
1979 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1980 ((Player
*)pVictim
)->UpdateDefense();
1982 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1984 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1986 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1987 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1991 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1993 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1994 StartReactiveTimer( REACTIVE_OVERPOWER
);
1997 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2000 case MELEE_HIT_BLOCK
:
2002 *blocked_amount
= pVictim
->GetShieldBlockValue();
2004 if (pVictim
->GetUnitBlockChance())
2005 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2007 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2009 //Only set VICTIMSTATE_BLOCK on a full block
2010 if (*blocked_amount
>= uint32(*damage
))
2012 *victimState
= VICTIMSTATE_BLOCKS
;
2013 *blocked_amount
= uint32(*damage
);
2016 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2019 ((Player
*)pVictim
)->UpdateDefense();
2021 // random durability for main hand weapon (BLOCK)
2022 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2023 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2026 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2027 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2031 case MELEE_HIT_GLANCING
:
2033 float reducePercent
= 1.0f
; //damage factor
2035 // calculate base values and mods
2036 float baseLowEnd
= 1.3;
2037 float baseHighEnd
= 1.2;
2038 switch(getClass()) // lowering base values for casters
2050 float maxLowEnd
= 0.6;
2051 switch(getClass()) // upper for melee classes
2055 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2059 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2060 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2061 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2063 // apply max/min bounds
2064 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2066 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2069 if ( highEnd
< 0.2f
) //high end limits
2071 if ( highEnd
> 0.99f
)
2074 if(lowEnd
> highEnd
) // prevent negative range size
2077 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2079 *damage
= uint32(reducePercent
* *damage
);
2080 cleanDamage
->damage
+= *damage
;
2081 *hitInfo
|= HITINFO_GLANCING
;
2084 case MELEE_HIT_CRUSHING
:
2086 // 150% normal damage
2087 *damage
+= (*damage
/ 2);
2088 cleanDamage
->damage
= *damage
;
2089 *hitInfo
|= HITINFO_CRUSHING
;
2090 // TODO: victimState, victim animation?
2097 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2098 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2100 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2101 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2104 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2105 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2107 cleanDamage
->damage
+= *blocked_amount
;
2109 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2111 //*hitInfo = 0x00010020;
2112 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2114 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2118 // update at damage Judgement aura duration that applied by attacker at victim
2121 AuraMap
const& vAuras
= pVictim
->GetAuras();
2122 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2124 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2125 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2126 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2128 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2129 (*itr
).second
->UpdateAuraDuration();
2134 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2136 // victim's damage shield
2137 // yet another hack to fix crashes related to the aura getting removed during iteration
2138 std::set
<Aura
*> alreadyDone
;
2139 uint32 removedAuras
= pVictim
->m_removedAuras
;
2140 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2141 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2144 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2146 alreadyDone
.insert(*i
);
2147 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2148 if (pVictim
->m_removedAuras
> removedAuras
)
2150 removedAuras
= pVictim
->m_removedAuras
;
2151 next
= vDamageShields
.begin();
2157 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2159 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2162 if (!pVictim
->isAlive())
2165 if(IsNonMeleeSpellCasted(false))
2169 if (attType
== BASE_ATTACK
)
2170 hitInfo
= HITINFO_NORMALSWING2
;
2171 else if (attType
== OFF_ATTACK
)
2172 hitInfo
= HITINFO_LEFTSWING
;
2174 return; // ignore ranged case
2176 uint32 extraAttacks
= m_extraAttacks
;
2178 // melee attack spell casted at main hand attack only
2179 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2181 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2183 // not recent extra attack only at any non extra attack (melee spell case)
2184 if(!extra
&& extraAttacks
)
2186 while(m_extraAttacks
)
2188 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2189 if(m_extraAttacks
> 0)
2197 VictimState victimState
= VICTIMSTATE_NORMAL
;
2199 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2200 uint32 blocked_dmg
= 0;
2201 uint32 absorbed_dmg
= 0;
2202 uint32 resisted_dmg
= 0;
2204 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2206 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2208 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2210 // not recent extra attack only at any non extra attack (miss case)
2211 if(!extra
&& extraAttacks
)
2213 while(m_extraAttacks
)
2215 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2216 if(m_extraAttacks
> 0)
2224 uint32 damage
= CalculateDamage (attType
, false);
2226 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2228 if (hitInfo
& HITINFO_MISS
)
2230 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2234 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2236 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2237 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2241 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2243 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2245 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2246 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2250 if (GetTypeId() == TYPEID_PLAYER
)
2251 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2252 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2254 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2255 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2257 // extra attack only at any non extra attack (normal case)
2258 if(!extra
&& extraAttacks
)
2260 while(m_extraAttacks
)
2262 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2263 if(m_extraAttacks
> 0)
2269 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2271 // Miss chance based on melee
2272 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2274 // Critical hit chance
2275 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2276 // this is to avoid compiler issue when declaring variables inside if
2277 float block_chance
, parry_chance
, dodge_chance
;
2279 // cannot be dodged/parried/blocked
2280 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2282 block_chance
= 0.0f
;
2283 parry_chance
= 0.0f
;
2284 dodge_chance
= 0.0f
;
2288 // parry can be avoided only by some abilities
2289 parry_chance
= pVictim
->GetUnitParryChance();
2290 // block might be bypassed by it as well
2291 block_chance
= pVictim
->GetUnitBlockChance();
2292 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2293 dodge_chance
= pVictim
->GetUnitDodgeChance();
2296 // Only players can have Talent&Spell bonuses
2297 if (GetTypeId() == TYPEID_PLAYER
)
2299 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2300 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2302 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents for speed
2304 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2305 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2307 // can't be dodged rogue finishing move
2308 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2310 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2312 dodge_chance
= 0.0f
;
2321 if(Player
* modOwner
= GetSpellModOwner())
2322 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2324 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2326 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
*100), int32(miss_chance
*100),int32(dodge_chance
*100),int32(parry_chance
*100),int32(block_chance
*100), true);
2329 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2331 // This is only wrapper
2333 // Miss chance based on melee
2334 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2336 // Critical hit chance
2337 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2339 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2340 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2341 float block_chance
= pVictim
->GetUnitBlockChance();
2342 float parry_chance
= pVictim
->GetUnitParryChance();
2344 // Useful if want to specify crit & miss chances for melee, else it could be removed
2345 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2347 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
*100), int32(miss_chance
*100), int32(dodge_chance
*100),int32(parry_chance
*100),int32(block_chance
*100), false);
2350 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, int32 crit_chance
, int32 miss_chance
, int32 dodge_chance
, int32 parry_chance
, int32 block_chance
, bool SpellCasted
) const
2352 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2353 return MELEE_HIT_EVADE
;
2355 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2356 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2358 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2359 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2361 // bonus from skills is 0.04%
2362 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2363 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2364 int32 sum
= 0, tmp
= 0;
2365 int32 roll
= urand (0, 10000);
2367 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2368 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2369 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2373 if (tmp
> 0 && roll
< (sum
+= tmp
))
2375 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2376 return MELEE_HIT_MISS
;
2379 // always crit against a sitting target (except 0 crit chance)
2380 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2383 return MELEE_HIT_CRIT
;
2388 // only players can't dodge if attacker is behind
2389 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2391 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2395 // Reduce dodge chance by attacker expertise rating
2396 if (GetTypeId() == TYPEID_PLAYER
)
2397 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2399 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2400 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2403 if ( (tmp
> 0) // check if unit _can_ dodge
2404 && ((tmp
-= skillBonus
) > 0)
2405 && roll
< (sum
+= tmp
))
2407 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2408 return MELEE_HIT_DODGE
;
2412 // parry & block chances
2414 // check if attack comes from behind, nobody can parry or block if attacker is behind
2415 if (!pVictim
->HasInArc(M_PI
,this))
2417 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2421 // Reduce parry chance by attacker expertise rating
2422 if (GetTypeId() == TYPEID_PLAYER
)
2423 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2425 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2427 int32 tmp
= int32(parry_chance
);
2428 if ( (tmp
> 0) // check if unit _can_ parry
2429 && ((tmp
-= skillBonus
) > 0)
2430 && (roll
< (sum
+= tmp
)))
2432 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2433 return MELEE_HIT_PARRY
;
2437 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2440 if ( (tmp
> 0) // check if unit _can_ block
2441 && ((tmp
-= skillBonus
) > 0)
2442 && (roll
< (sum
+= tmp
)))
2445 tmp
= crit_chance
+ skillBonus2
;
2446 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2448 if ( roll_chance_i(tmp
/100))
2450 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2451 return MELEE_HIT_BLOCK_CRIT
;
2454 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2455 return MELEE_HIT_BLOCK
;
2461 tmp
= crit_chance
+ skillBonus2
;
2463 if (tmp
> 0 && roll
< (sum
+= tmp
))
2465 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2466 return MELEE_HIT_CRIT
;
2469 // 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)
2470 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2471 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2472 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2473 getLevel() < pVictim
->getLevelForTarget(this) )
2475 // cap possible value (with bonuses > max skill)
2476 int32 skill
= attackerWeaponSkill
;
2477 int32 maxskill
= attackerMaxSkillValueForLevel
;
2478 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2480 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2481 tmp
= tmp
> 4000 ? 4000 : tmp
;
2482 if (roll
< (sum
+= tmp
))
2484 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2485 return MELEE_HIT_GLANCING
;
2489 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2491 // mobs can score crushing blows if they're 3 or more levels above victim
2492 // or when their weapon skill is 15 or more above victim's defense skill
2493 tmp
= victimDefenseSkill
;
2494 int32 tmpmax
= victimMaxSkillValueForLevel
;
2495 // having defense above your maximum (from items, talents etc.) has no effect
2496 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2497 // tmp = mob's level * 5 - player's current defense skill
2498 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2501 // add 2% chance per lacking skill point, min. is 15%
2502 tmp
= tmp
* 200 - 1500;
2503 if (roll
< (sum
+= tmp
))
2505 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2506 return MELEE_HIT_CRUSHING
;
2511 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2512 return MELEE_HIT_NORMAL
;
2515 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2517 float min_damage
, max_damage
;
2519 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2520 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2526 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2527 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2530 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2531 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2534 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2535 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2537 // Just for good manner
2545 if (min_damage
> max_damage
)
2547 std::swap(min_damage
,max_damage
);
2550 if(max_damage
== 0.0f
)
2553 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2556 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2558 if(spellProto
->spellLevel
<= 0)
2561 float LvlPenalty
= 0.0f
;
2563 if(spellProto
->spellLevel
< 20)
2564 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2565 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2566 if(LvlFactor
> 1.0f
)
2569 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2572 void Unit::SendAttackStart(Unit
* pVictim
)
2574 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2575 data
<< uint64(GetGUID());
2576 data
<< uint64(pVictim
->GetGUID());
2578 SendMessageToSet(&data
, true);
2579 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2582 void Unit::SendAttackStop(Unit
* victim
)
2587 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2588 data
.append(GetPackGUID());
2589 data
.append(victim
->GetPackGUID()); // can be 0x00...
2590 data
<< uint32(0); // can be 0x1
2591 SendMessageToSet(&data
, true);
2592 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2594 /*if(victim->GetTypeId() == TYPEID_UNIT)
2595 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2599 // Melee based spells can be miss, parry or dodge on this step
2600 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2601 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2603 // Calculate hit chance (more correct for chance mod)
2606 // PvP - PvE melee chances
2607 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2608 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2610 HitChance = 95 - leveldif;
2612 HitChance = 93 - (leveldif - 2) * lchance;
2614 // Hit chance depends from victim auras
2615 if(attType == RANGED_ATTACK)
2616 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2618 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2620 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2621 if(Player *modOwner = GetSpellModOwner())
2622 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2625 float miss_chance= 100.0f - HitChance;
2627 // Bonuses from attacker aura and ratings
2628 if (attType == RANGED_ATTACK)
2629 miss_chance -= m_modRangedHitChance;
2631 miss_chance -= m_modMeleeHitChance;
2633 // bonus from skills is 0.04%
2634 miss_chance -= skillDiff * 0.04f;
2636 // Limit miss chance from 0 to 60%
2637 if (miss_chance < 0.0f)
2639 if (miss_chance > 60.0f)
2644 // Melee based spells hit result calculations
2645 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2647 WeaponAttackType attType = BASE_ATTACK;
2649 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2650 attType = RANGED_ATTACK;
2652 // bonus from skills is 0.04% per skill Diff
2653 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2654 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2655 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2657 uint32 roll = urand (0, 10000);
2658 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2661 uint32 tmp = missChance;
2663 return SPELL_MISS_MISS;
2665 // Same spells cannot be parry/dodge
2666 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2667 return SPELL_MISS_NONE;
2669 // Ranged attack can`t miss too
2670 if (attType == RANGED_ATTACK)
2671 return SPELL_MISS_NONE;
2673 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2676 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2677 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2678 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2680 // Reduce dodge chance by attacker expertise rating
2681 if (GetTypeId() == TYPEID_PLAYER)
2682 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2683 if (dodgeChance < 0)
2686 // Can`t dodge from behind in PvP (but its possible in PvE)
2687 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2690 // Rogue talent`s cant be dodged
2691 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2692 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2694 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2696 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2706 return SPELL_MISS_DODGE;
2709 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2710 // Reduce parry chance by attacker expertise rating
2711 if (GetTypeId() == TYPEID_PLAYER)
2712 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2713 // Can`t parry from behind
2714 if (parryChance < 0 || attackFromBehind)
2719 return SPELL_MISS_PARRY;
2721 return SPELL_MISS_NONE;
2724 // TODO need use unit spell resistances in calculations
2725 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2727 // Can`t miss on dead target (on skinning for example)
2728 if (!pVictim
->isAlive())
2729 return SPELL_MISS_NONE
;
2731 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2732 // PvP - PvE spell misschances per leveldif > 2
2733 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2734 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2736 // Base hit chance from attacker and victim levels
2739 modHitChance
= 96 - leveldif
;
2741 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2743 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2744 if(Player
*modOwner
= GetSpellModOwner())
2745 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2746 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2747 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2748 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2749 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2750 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2751 if (IsAreaOfEffectSpell(spell
))
2752 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2753 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2754 if (IsDispelSpell(spell
))
2755 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2756 // Chance resist mechanic (select max value from every mechanic spell effect)
2757 int32 resist_mech
= 0;
2758 // Get effects mechanic and chance
2759 for(int eff
= 0; eff
< 3; ++eff
)
2761 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2764 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2765 if (resist_mech
< temp
)
2770 modHitChance
-=resist_mech
;
2772 // Chance resist debuff
2773 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2775 int32 HitChance
= modHitChance
* 100;
2776 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2777 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2779 // Decrease hit chance from victim rating bonus
2780 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2781 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2783 if (HitChance
< 100) HitChance
= 100;
2784 if (HitChance
> 9900) HitChance
= 9900;
2786 uint32 rand
= urand(0,10000);
2787 if (rand
> HitChance
)
2788 return SPELL_MISS_RESIST
;
2789 return SPELL_MISS_NONE
;
2792 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2794 // Return evade for units in evade mode
2795 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2796 return SPELL_MISS_EVADE
;
2798 // Check for immune (use charges)
2799 if (pVictim
->IsImmunedToSpell(spell
,true))
2800 return SPELL_MISS_IMMUNE
;
2802 // All positive spells can`t miss
2803 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2804 if (IsPositiveSpell(spell
->Id
))
2805 return SPELL_MISS_NONE
;
2807 // Check for immune (use charges)
2808 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2809 return SPELL_MISS_IMMUNE
;
2811 // Try victim reflect spell
2814 // specialized first
2815 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2816 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2818 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2820 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2821 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2823 if((*i
)->m_procCharges
> 0)
2825 --(*i
)->m_procCharges
;
2826 if((*i
)->m_procCharges
==0)
2827 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2829 return SPELL_MISS_REFLECT
;
2834 // generic reflection
2835 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2836 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2838 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2839 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2841 if((*i
)->m_procCharges
> 0)
2843 --(*i
)->m_procCharges
;
2844 if((*i
)->m_procCharges
==0)
2845 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2847 return SPELL_MISS_REFLECT
;
2852 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2853 for (int i
=0;i
<3;i
++)
2855 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2856 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2857 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2858 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2859 return SPELL_MISS_NONE
;
2862 // TODO need use this code for spell hit result calculation
2863 // now code commented for computability
2864 switch (spell
->DmgClass
)
2866 case SPELL_DAMAGE_CLASS_RANGED
:
2867 case SPELL_DAMAGE_CLASS_MELEE
:
2868 // return MeleeSpellHitResult(pVictim, spell);
2869 return SPELL_MISS_NONE
;
2870 case SPELL_DAMAGE_CLASS_NONE
:
2871 case SPELL_DAMAGE_CLASS_MAGIC
:
2872 return MagicSpellHitResult(pVictim
, spell
);
2874 return SPELL_MISS_NONE
;
2877 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2882 // Base misschance 5%
2883 float misschance
= 5.0f
;
2885 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2886 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2888 bool isNormal
= false;
2889 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2891 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2897 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2907 // PvP : PvE melee misschances per leveldif > 2
2908 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2910 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2914 // Hit chance from attacker based on ratings and auras
2915 float m_modHitChance
;
2916 if (attType
== RANGED_ATTACK
)
2917 m_modHitChance
= m_modRangedHitChance
;
2919 m_modHitChance
= m_modMeleeHitChance
;
2922 misschance
+= (leveldif
- m_modHitChance
);
2924 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2926 // Hit chance for victim based on ratings
2927 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2929 if (attType
== RANGED_ATTACK
)
2930 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2932 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2935 // Modify miss chance by victim auras
2936 if(attType
== RANGED_ATTACK
)
2937 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2939 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2941 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2942 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2943 misschance
-= skillBonus
* 0.04f
;
2945 // Limit miss chance from 0 to 60%
2946 if ( misschance
< 0.0f
)
2948 if ( misschance
> 60.0f
)
2954 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2956 if(GetTypeId() == TYPEID_PLAYER
)
2958 // in PvP use full skill instead current skill value
2959 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2960 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2961 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2962 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2966 return GetUnitMeleeSkill(target
);
2969 float Unit::GetUnitDodgeChance() const
2971 if(hasUnitState(UNIT_STAT_STUNNED
))
2973 if( GetTypeId() == TYPEID_PLAYER
)
2974 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2977 if(((Creature
const*)this)->isTotem())
2982 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2983 return dodge
> 0.0f
? dodge
: 0.0f
;
2988 float Unit::GetUnitParryChance() const
2990 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
2993 float chance
= 0.0f
;
2995 if(GetTypeId() == TYPEID_PLAYER
)
2997 Player
const* player
= (Player
const*)this;
2998 if(player
->CanParry() )
3000 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3002 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3005 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3008 else if(GetTypeId() == TYPEID_UNIT
)
3010 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3013 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3017 return chance
> 0.0f
? chance
: 0.0f
;
3020 float Unit::GetUnitBlockChance() const
3022 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3025 if(GetTypeId() == TYPEID_PLAYER
)
3027 Player
const* player
= (Player
const*)this;
3028 if(player
->CanBlock() )
3030 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3031 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3032 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3034 // is player but has no block ability or no not broken shield equipped
3039 if(((Creature
const*)this)->isTotem())
3044 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3045 return block
> 0.0f
? block
: 0.0f
;
3050 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3054 if(GetTypeId() == TYPEID_PLAYER
)
3059 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3062 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3065 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3067 // Just for good manner
3076 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3080 if(attackType
== RANGED_ATTACK
)
3081 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3083 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3085 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3087 // reduce crit chance from Rating for players
3088 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3090 if (attackType
==RANGED_ATTACK
)
3091 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3093 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3101 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3104 if(GetTypeId() == TYPEID_PLAYER
)
3106 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3108 // feral or unarmed skill only for base attack
3109 if(attType
!= BASE_ATTACK
&& !item
)
3112 if(((Player
*)this)->IsInFeralForm())
3113 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3115 // weapon skill or (unarmed for base attack)
3116 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3118 // in PvP use full skill instead current skill value
3119 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3120 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3121 : ((Player
*)this)->GetSkillValue(skill
);
3122 // Modify value from ratings
3123 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3126 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3127 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3128 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3132 value
= GetUnitMeleeSkill(target
);
3136 void Unit::_UpdateSpells( uint32 time
)
3138 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3139 _UpdateAutoRepeatSpell();
3141 // remove finished spells from current pointers
3142 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3144 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3146 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3147 m_currentSpells
[i
] = NULL
; // remove pointer
3151 // TODO: Find a better way to prevent crash when multiple auras are removed.
3153 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3155 (*i
).second
->SetUpdated(false);
3157 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3163 // prevent double update
3164 if ((*i
).second
->IsUpdated())
3166 (*i
).second
->SetUpdated(true);
3167 (*i
).second
->Update( time
);
3168 // several auras can be deleted due to update
3171 if (m_Auras
.empty()) break;
3172 next
= m_Auras
.begin();
3178 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3182 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3197 if(!m_gameObj
.empty())
3199 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3200 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3203 //(*i)->Update( difftime );
3204 if( !(*ite1
)->isSpawned() )
3206 (*ite1
)->SetOwnerGUID(0);
3207 (*ite1
)->SetRespawnTime(0);
3209 dnext1
= m_gameObj
.erase(ite1
);
3217 void Unit::_UpdateAutoRepeatSpell()
3219 //check "realtime" interrupts
3220 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3222 // cancel wand shoot
3223 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3224 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3225 m_AutoRepeatFirstCast
= true;
3230 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3231 setAttackTimer(RANGED_ATTACK
,500);
3232 m_AutoRepeatFirstCast
= false;
3235 if (isAttackReady(RANGED_ATTACK
))
3237 // Check if able to cast
3238 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3240 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3245 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3246 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3248 // all went good, reset attack
3249 resetAttackTimer(RANGED_ATTACK
);
3253 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3255 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3257 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3259 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3261 // break same type spell if it is not delayed
3262 InterruptSpell(CSpellType
,false);
3264 // special breakage effects:
3267 case CURRENT_GENERIC_SPELL
:
3269 // generic spells always break channeled not delayed spells
3270 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3272 // autorepeat breaking
3273 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3275 // break autorepeat if not Auto Shot
3276 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3277 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3278 m_AutoRepeatFirstCast
= true;
3282 case CURRENT_CHANNELED_SPELL
:
3284 // channel spells always break generic non-delayed and any channeled spells
3285 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3286 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3288 // it also does break autorepeat if not Auto Shot
3289 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3290 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3291 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3294 case CURRENT_AUTOREPEAT_SPELL
:
3296 // only Auto Shoot does not break anything
3297 if (pSpell
->m_spellInfo
->Category
== 351)
3299 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3300 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3301 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3303 // special action: set first cast flag
3304 m_AutoRepeatFirstCast
= true;
3309 // other spell types don't break anything now
3313 // current spell (if it is still here) may be safely deleted now
3314 if (m_currentSpells
[CSpellType
])
3315 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3317 // set new current spell
3318 m_currentSpells
[CSpellType
] = pSpell
;
3319 pSpell
->SetReferencedFromCurrent(true);
3322 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3324 assert(spellType
< CURRENT_MAX_SPELL
);
3326 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3328 // send autorepeat cancel message for autorepeat spells
3329 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3331 if(GetTypeId()==TYPEID_PLAYER
)
3332 ((Player
*)this)->SendAutoRepeatCancel();
3335 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3336 m_currentSpells
[spellType
]->cancel();
3337 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3338 m_currentSpells
[spellType
] = NULL
;
3342 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3344 // We don't do loop here to explicitly show that melee spell is excluded.
3345 // Maybe later some special spells will be excluded too.
3347 // generic spells are casted when they are not finished and not delayed
3348 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3349 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3350 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3353 // channeled spells may be delayed, but they are still considered casted
3354 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3355 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3358 // autorepeat spells may be finished or delayed, but they are still considered casted
3359 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3365 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3367 // generic spells are interrupted if they are not finished or delayed
3368 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3370 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3371 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3372 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3373 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3374 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3377 // autorepeat spells are interrupted if they are not finished or delayed
3378 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3380 // send disable autorepeat packet in any case
3381 if(GetTypeId()==TYPEID_PLAYER
)
3382 ((Player
*)this)->SendAutoRepeatCancel();
3384 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3385 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3386 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3387 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3388 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3391 // channeled spells are interrupted if they are not finished, even if they are delayed
3392 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3394 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3395 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3396 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3397 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3401 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3403 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3404 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3405 return m_currentSpells
[i
];
3409 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3411 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3414 void Unit::SetInFront(Unit
const* target
)
3416 SetOrientation(GetAngle(target
));
3419 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3421 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3424 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3427 return c
->canSwim();
3429 return c
->canWalk() || c
->canFly();
3432 bool Unit::IsInWater() const
3434 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3437 bool Unit::IsUnderWater() const
3439 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3442 void Unit::DeMorph()
3444 SetDisplayId(GetNativeDisplayId());
3447 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3451 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3452 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3453 modifier
+= (*i
)->GetModifier()->m_amount
;
3458 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3460 float multiplier
= 1.0f
;
3462 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3463 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3464 multiplier
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3469 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3473 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3474 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3475 if ((*i
)->GetModifier()->m_amount
> modifier
)
3476 modifier
= (*i
)->GetModifier()->m_amount
;
3481 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3485 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3486 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3487 if ((*i
)->GetModifier()->m_amount
< modifier
)
3488 modifier
= (*i
)->GetModifier()->m_amount
;
3493 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3497 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3498 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3500 Modifier
* mod
= (*i
)->GetModifier();
3501 if (mod
->m_miscvalue
& misc_mask
)
3502 modifier
+= mod
->m_amount
;
3507 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3509 float multiplier
= 1.0f
;
3511 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3512 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3514 Modifier
* mod
= (*i
)->GetModifier();
3515 if (mod
->m_miscvalue
& misc_mask
)
3516 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3521 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3525 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3526 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3528 Modifier
* mod
= (*i
)->GetModifier();
3529 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3530 modifier
= mod
->m_amount
;
3536 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3540 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3541 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3543 Modifier
* mod
= (*i
)->GetModifier();
3544 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3545 modifier
= mod
->m_amount
;
3551 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3555 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3556 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3558 Modifier
* mod
= (*i
)->GetModifier();
3559 if (mod
->m_miscvalue
== misc_value
)
3560 modifier
+= mod
->m_amount
;
3565 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3567 float multiplier
= 1.0f
;
3569 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3570 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3572 Modifier
* mod
= (*i
)->GetModifier();
3573 if (mod
->m_miscvalue
== misc_value
)
3574 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3579 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3583 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3584 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3586 Modifier
* mod
= (*i
)->GetModifier();
3587 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3588 modifier
= mod
->m_amount
;
3594 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3598 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3599 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3601 Modifier
* mod
= (*i
)->GetModifier();
3602 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3603 modifier
= mod
->m_amount
;
3609 bool Unit::AddAura(Aura
*Aur
)
3611 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3612 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3613 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3619 if(Aur
->GetTarget() != this)
3621 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3622 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3623 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3628 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3630 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3631 AuraMap::iterator i
= m_Auras
.find( spair
);
3633 // take out same spell
3634 if (i
!= m_Auras
.end())
3636 // passive and persistent auras can stack with themselves any number of times
3637 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3639 // replace aura if next will > spell StackAmount
3640 if(aurSpellInfo
->StackAmount
)
3642 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3643 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3645 // if StackAmount==0 not allow auras from same caster
3648 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3650 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3652 // can be only single (this check done at _each_ aura add
3653 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3658 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3661 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3662 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3663 case SPELL_AURA_PERIODIC_LEECH
:
3664 case SPELL_AURA_PERIODIC_HEAL
:
3665 case SPELL_AURA_OBS_MOD_HEALTH
:
3666 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3667 case SPELL_AURA_PERIODIC_ENERGIZE
:
3668 case SPELL_AURA_OBS_MOD_MANA
:
3669 case SPELL_AURA_POWER_BURN_MANA
:
3671 default: // not allow
3672 // can be only single (this check done at _each_ aura add
3673 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3685 // passive auras stack with all (except passive spell proc auras)
3686 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3687 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3689 if (!RemoveNoStackAurasDueToAura(Aur
))
3692 return false; // couldn't remove conflicting aura with higher rank
3696 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3697 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3699 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3702 Unit
* caster
= Aur
->GetCaster();
3703 if(!caster
) // caster deleted and not required adding scAura
3706 bool restart
= false;
3707 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3708 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3710 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3711 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3713 if ((*itr
)->IsInUse())
3715 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());
3718 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3727 scAuras
.push_back(Aur
);
3733 // add aura, register in lists and arrays
3735 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3736 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3738 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3741 Aur
->ApplyModifier(true,true);
3742 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3746 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3748 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3751 AuraMap::iterator i
,next
;
3752 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3756 uint32 i_spellId
= (*i
).second
->GetId();
3757 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3759 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3761 RemoveAurasDueToSpell(i_spellId
);
3763 if( m_Auras
.empty() )
3766 next
= m_Auras
.begin();
3772 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3777 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3781 uint32 spellId
= Aur
->GetId();
3782 uint32 effIndex
= Aur
->GetEffIndex();
3784 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3786 AuraMap::iterator i
,next
;
3787 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3791 if (!(*i
).second
) continue;
3793 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3798 uint32 i_spellId
= i_spellProto
->Id
;
3800 if(IsPassiveSpell(i_spellId
))
3802 if(IsPassiveStackableSpell(i_spellId
))
3805 // passive non-stackable spells not stackable only with another rank of same spell
3806 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3810 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3812 if(i_spellId
== spellId
) continue;
3814 bool is_triggered_by_spell
= false;
3815 // prevent triggered aura of removing aura that triggered it
3816 for(int j
= 0; j
< 3; ++j
)
3817 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3818 is_triggered_by_spell
= true;
3819 if (is_triggered_by_spell
) continue;
3821 for(int j
= 0; j
< 3; ++j
)
3823 // prevent remove dummy triggered spells at next effect aura add
3824 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggered spell
3826 case SPELL_EFFECT_DUMMY
:
3829 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3834 if(is_triggered_by_spell
)
3837 // prevent remove form main spell by triggered passive spells
3838 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3840 case SPELL_AURA_MOD_SHAPESHIFT
:
3843 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3844 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3845 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3851 if(!is_triggered_by_spell
)
3853 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3855 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3857 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3859 // cannot remove higher rank
3860 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3861 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3864 // Its a parent aura (create this aura in ApplyModifier)
3865 if ((*i
).second
->IsInUse())
3867 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());
3870 RemoveAurasDueToSpell(i_spellId
);
3872 if( m_Auras
.empty() )
3875 next
= m_Auras
.begin();
3877 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3879 // Its a parent aura (create this aura in ApplyModifier)
3880 if ((*i
).second
->IsInUse())
3882 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());
3885 RemoveAurasDueToSpell(i_spellId
);
3887 if( m_Auras
.empty() )
3890 next
= m_Auras
.begin();
3892 // Potions stack aura by aura (elixirs/flask already checked)
3893 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3895 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3897 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3898 return false; // cannot remove higher rank
3900 // Its a parent aura (create this aura in ApplyModifier)
3901 if ((*i
).second
->IsInUse())
3903 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());
3915 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3917 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3918 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3920 if(iter
->second
!=except
)
3923 iter
= m_Auras
.lower_bound(spair
);
3930 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3932 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3934 Aura
*aur
= iter
->second
;
3935 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3937 // Custom dispel case
3938 // Unstable Affliction
3939 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3941 int32 damage
= aur
->GetModifier()->m_amount
*9;
3942 uint64 caster_guid
= aur
->GetCasterGUID();
3945 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3947 // backfire damage and silence
3948 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3950 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3953 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3960 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3962 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3964 Aura
*aur
= iter
->second
;
3965 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3967 int32 basePoints
= aur
->GetBasePoints();
3968 // construct the new aura for the attacker
3969 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3973 // set its duration and maximum duration
3974 // max duration 2 minutes (in msecs)
3975 int32 dur
= aur
->GetAuraDuration();
3976 const int32 max_dur
= 2*MINUTE
*1000;
3977 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3978 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3980 // add the new aura to stealer
3981 stealer
->AddAura(new_aur
);
3983 // Remove aura as dispel
3984 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3991 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
3993 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3995 if (iter
->second
->GetId() == spellId
)
3996 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4002 void Unit::RemoveAurasWithDispelType( DispelType type
)
4004 // Create dispel mask by dispel type
4005 uint32 dispelMask
= GetDispellMask(type
);
4006 // Dispel all existing auras vs current dispel type
4007 AuraMap
& auras
= GetAuras();
4008 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4010 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4011 if( (1<<spell
->Dispel
) & dispelMask
)
4014 RemoveAurasDueToSpell(spell
->Id
);
4015 itr
= auras
.begin();
4022 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4024 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4025 if(iter
!= m_Auras
.end())
4029 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4031 for (int i
= 0; i
< 3; ++i
)
4032 RemoveAura(spellId
,i
,except
);
4035 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4037 for (int k
=0; k
< 3; ++k
)
4039 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4040 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4042 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4045 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4053 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4055 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4057 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4064 void Unit::RemoveNotOwnSingleTargetAuras()
4066 // single target auras from other casters
4067 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4069 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4075 // single target auras at other targets
4076 AuraList
& scAuras
= GetSingleCastAuras();
4077 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4080 if (aura
->GetTarget()!=this)
4082 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4083 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4084 iter
= scAuras
.begin();
4092 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4094 Aura
* Aur
= i
->second
;
4095 SpellEntry
const* AurSpellInfo
= Aur
->GetSpellProto();
4097 Unit
* caster
= NULL
;
4098 if (IsSingleTargetSpell(AurSpellInfo
))
4100 caster
= Aur
->GetCaster();
4103 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4104 scAuras
.remove(Aur
);
4108 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4113 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4114 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4116 m_modAuras
[Aur
->GetModifier()->m_auraname
].remove(Aur
);
4120 Aur
->SetRemoveMode(mode
);
4121 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4122 // remove aura from list before to prevent deleting it before
4124 ++m_removedAuras
; // internal count used by unit update
4126 // Statue unsummoned at aura remove
4127 Totem
* statue
= NULL
;
4128 bool caster_channeled
= false;
4129 if(IsChanneledSpell(AurSpellInfo
))
4131 if(!caster
) // can be already located for IsSingleTargetSpell case
4132 caster
= Aur
->GetCaster();
4136 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4137 statue
= ((Totem
*)caster
);
4139 caster_channeled
= caster
==this;
4143 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4144 Aur
->ApplyModifier(false,true);
4148 if(caster_channeled
)
4149 RemoveAurasAtChanneledTarget (AurSpellInfo
);
4154 // only way correctly remove all auras from list
4155 if( m_Auras
.empty() )
4158 i
= m_Auras
.begin();
4161 void Unit::RemoveAllAuras()
4163 while (!m_Auras
.empty())
4165 AuraMap::iterator iter
= m_Auras
.begin();
4170 void Unit::RemoveArenaAuras(bool onleave
)
4172 // in join, remove positive buffs, on end, remove negative
4173 // used to remove positive visible auras in arenas
4174 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4176 if ( !(iter
->second
->GetSpellProto()->AttributesEx4
& (1<<21)) // don't remove stances, shadowform, pally/hunter auras
4177 && !iter
->second
->IsPassive() // don't remove passive auras
4178 && (!(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)
4179 && (iter
->second
->IsPositive() ^ onleave
)) // remove positive buffs on enter, negative buffs on leave
4186 void Unit::RemoveAllAurasOnDeath()
4188 // used just after dieing to remove all visible auras
4189 // and disable the mods for the passive ones
4190 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4192 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4193 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4199 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4201 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4202 if (iter
!= m_Auras
.end())
4204 if (iter
->second
->GetAuraDuration() < delaytime
)
4205 iter
->second
->SetAuraDuration(0);
4207 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4208 iter
->second
->UpdateAuraDuration();
4209 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4213 void Unit::_RemoveAllAuraMods()
4215 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4217 (*i
).second
->ApplyModifier(false);
4221 void Unit::_ApplyAllAuraMods()
4223 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4225 (*i
).second
->ApplyModifier(true);
4229 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4231 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4232 if (iter
!= m_Auras
.end())
4233 return iter
->second
;
4237 void Unit::AddDynObject(DynamicObject
* dynObj
)
4239 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4242 void Unit::RemoveDynObject(uint32 spellid
)
4244 if(m_dynObjGUIDs
.empty())
4246 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4248 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4251 i
= m_dynObjGUIDs
.erase(i
);
4253 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4256 i
= m_dynObjGUIDs
.erase(i
);
4263 void Unit::RemoveAllDynObjects()
4265 while(!m_dynObjGUIDs
.empty())
4267 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4270 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4274 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4276 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4278 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4281 i
= m_dynObjGUIDs
.erase(i
);
4285 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4292 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4294 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4296 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4299 i
= m_dynObjGUIDs
.erase(i
);
4303 if (dynObj
->GetSpellId() == spellId
)
4310 void Unit::AddGameObject(GameObject
* gameObj
)
4312 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4313 m_gameObj
.push_back(gameObj
);
4314 gameObj
->SetOwnerGUID(GetGUID());
4317 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4319 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4321 // GO created by some spell
4322 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4324 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4325 // Need activate spell use for owner
4326 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4327 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4329 gameObj
->SetOwnerGUID(0);
4330 m_gameObj
.remove(gameObj
);
4333 gameObj
->SetRespawnTime(0);
4338 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4340 if(m_gameObj
.empty())
4342 std::list
<GameObject
*>::iterator i
, next
;
4343 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4346 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4348 (*i
)->SetOwnerGUID(0);
4351 (*i
)->SetRespawnTime(0);
4355 next
= m_gameObj
.erase(i
);
4362 void Unit::RemoveAllGameObjects()
4364 // remove references to unit
4365 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4367 (*i
)->SetOwnerGUID(0);
4368 (*i
)->SetRespawnTime(0);
4370 i
= m_gameObj
.erase(i
);
4374 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4376 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4377 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4378 data
.append(target
->GetPackGUID());
4379 data
.append(GetPackGUID());
4380 data
<< uint32(SpellID
);
4381 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4382 data
<< uint8(damageSchoolMask
); // spell school
4383 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4384 data
<< uint32(Resist
); // resist
4385 data
<< uint8(PhysicalDamage
); // 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
4386 data
<< uint8(0); // unk isFromAura
4387 data
<< uint32(Blocked
); // blocked
4388 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4389 data
<< uint8(0); // isDebug?
4390 SendMessageToSet( &data
, true );
4393 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4395 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4396 data
<< uint32(spellID
);
4397 data
<< uint64(GetGUID());
4398 data
<< uint8(0); // can be 0 or 1
4399 data
<< uint32(1); // target count
4400 // for(i = 0; i < target count; ++i)
4401 data
<< uint64(target
->GetGUID()); // target GUID
4402 data
<< uint8(missInfo
);
4404 SendMessageToSet(&data
, true);
4407 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4409 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4411 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4412 data
<< (uint32
)HitInfo
;
4413 data
.append(GetPackGUID());
4414 data
.append(target
->GetPackGUID());
4415 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4417 data
<< (uint8
)SwingType
; // count?
4419 // for(i = 0; i < SwingType; ++i)
4420 data
<< (uint32
)damageSchoolMask
;
4421 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4422 // still need to double check damage
4423 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4424 data
<< (uint32
)AbsorbDamage
;
4425 data
<< (uint32
)Resist
;
4428 data
<< (uint32
)TargetState
;
4430 if( AbsorbDamage
== 0 ) //also 0x3E8 = 0x3E8, check when that happens
4436 data
<< (uint32
)BlockedAmount
;
4438 SendMessageToSet( &data
, true );
4441 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4443 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4445 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4447 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4448 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4449 // That is the question though if it's fully correct
4450 if(procSpell
&& !isTriggeredSpell
)
4452 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4454 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4455 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4456 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4457 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4458 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4460 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4462 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4463 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4464 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4465 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4466 attType
= RANGED_ATTACK
;
4469 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4470 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4472 // Not much to do if no flags are set.
4475 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4476 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4477 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4480 // Now go on with a victim's events'n'auras
4481 // Not much to do if no flags are set or there is no victim
4482 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4484 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4485 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4486 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4490 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4495 uint32 procAttacker
= PROC_FLAG_NONE
;
4496 uint32 procVictim
= PROC_FLAG_NONE
;
4500 case MELEE_HIT_EVADE
:
4502 case MELEE_HIT_MISS
:
4503 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4505 procAttacker
= PROC_FLAG_MISS
;
4508 case MELEE_HIT_BLOCK_CRIT
:
4509 case MELEE_HIT_CRIT
:
4510 if(spellCasted
&& attType
== BASE_ATTACK
)
4512 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4513 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4514 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4516 procVictim
|= PROC_FLAG_BLOCK
;
4517 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4520 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4522 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4523 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4527 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4528 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4531 case MELEE_HIT_PARRY
:
4532 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4533 procVictim
= PROC_FLAG_PARRY
;
4535 case MELEE_HIT_BLOCK
:
4536 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4537 procVictim
= PROC_FLAG_BLOCK
;
4539 case MELEE_HIT_DODGE
:
4540 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4541 procVictim
= PROC_FLAG_DODGE
;
4543 case MELEE_HIT_CRUSHING
:
4544 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4546 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4547 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4551 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4552 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4556 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4558 procAttacker
= PROC_FLAG_HIT_MELEE
;
4559 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4563 procAttacker
= PROC_FLAG_HIT_RANGED
;
4564 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4570 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4572 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4573 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4576 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4578 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4580 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4581 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4583 uint32 triggered_spell_id
= 0;
4584 Unit
* target
= pVictim
;
4585 int32 basepoints0
= 0;
4587 switch(hasteSpell
->SpellFamilyName
)
4589 case SPELLFAMILY_ROGUE
:
4591 switch(hasteSpell
->Id
)
4597 target
= SelectNearbyTarget();
4600 basepoints0
= damage
;
4601 triggered_spell_id
= 22482;
4609 // processed charge only counting case
4610 if(!triggered_spell_id
)
4613 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4617 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4622 if(!target
|| target
!=this && !target
->isAlive())
4625 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4629 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4631 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4633 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4634 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4639 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4641 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4642 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4644 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4645 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4647 uint32 triggered_spell_id
= 0;
4648 Unit
* target
= pVictim
;
4649 int32 basepoints0
= 0;
4651 switch(dummySpell
->SpellFamilyName
)
4653 case SPELLFAMILY_GENERIC
:
4655 switch (dummySpell
->Id
)
4661 // prevent damage back from weapon special attacks
4662 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4665 // return damage % to attacker but < 50% own total health
4666 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4667 if(basepoints0
> GetMaxHealth()/2)
4668 basepoints0
= GetMaxHealth()/2;
4670 triggered_spell_id
= 25997;
4678 // prevent chain of triggered spell from same triggered spell
4679 if(procSpell
&& procSpell
->Id
==26654)
4682 target
= SelectNearbyTarget();
4686 triggered_spell_id
= 26654;
4692 if (!procSpell
|| procSpell
->Id
== 24659)
4694 // Need remove one 24659 aura
4695 RemoveSingleAuraFromStack(24659, 0);
4696 RemoveSingleAuraFromStack(24659, 1);
4699 // Restless Strength
4702 // Need remove one 24662 aura
4703 RemoveSingleAuraFromStack(24662, 0);
4706 // Adaptive Warding (Frostfire Regalia set)
4714 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4715 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4717 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4719 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4729 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4731 case SPELL_SCHOOL_NORMAL
:
4732 case SPELL_SCHOOL_HOLY
:
4733 return false; // ignored
4734 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4735 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4736 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4737 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4738 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4746 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4754 for(int j
= 0; j
< 3; ++j
)
4756 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4765 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4767 case SPELL_SCHOOL_NORMAL
:
4768 return false; // ignore
4769 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4770 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4771 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4772 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4773 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4774 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4782 // Mana Leech (Passive) (Priest Pet Aura)
4786 target
= GetOwner();
4790 basepoints0
= int32(damage
* 2.5f
); // manaregen
4791 triggered_spell_id
= 34650;
4797 // Cast finish spell at last charge
4798 if (triggeredByAura
->m_procCharges
> 1)
4802 triggered_spell_id
= 33494;
4805 // Twisted Reflection (boss spell)
4807 triggered_spell_id
= 21064;
4809 // Vampiric Aura (boss spell)
4812 basepoints0
= 3 * damage
; // 300%
4813 if (basepoints0
< 0)
4816 triggered_spell_id
= 31285;
4820 // Aura of Madness (Darkmoon Card: Madness trinket)
4821 //=====================================================
4822 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4823 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4824 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4825 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4826 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4827 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4828 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4829 // 41011 Martyr Complex: +35 stamina (All classes)
4830 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4831 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4834 if(GetTypeId() != TYPEID_PLAYER
)
4837 // Select class defined buff
4840 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4841 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4843 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4844 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4847 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4848 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4850 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4851 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4854 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4855 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4856 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4857 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4859 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4860 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4863 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4865 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4866 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4874 if (roll_chance_i(10))
4875 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4879 // TODO: need find item for aura and triggered spells
4880 // Sunwell Exalted Caster Neck (??? neck)
4881 // cast ??? Light's Wrath if Exalted by Aldor
4882 // cast ??? Arcane Bolt if Exalted by Scryers*/
4884 return false; // disable for while
4887 if(GetTypeId() != TYPEID_PLAYER)
4890 // Get Aldor reputation rank
4891 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4894 triggered_spell_id = ???
4897 // Get Scryers reputation rank
4898 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4900 triggered_spell_id = ???
4905 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4906 // cast 45479 Light's Wrath if Exalted by Aldor
4907 // cast 45429 Arcane Bolt if Exalted by Scryers
4910 if(GetTypeId() != TYPEID_PLAYER
)
4913 // Get Aldor reputation rank
4914 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4917 triggered_spell_id
= 45479;
4920 // Get Scryers reputation rank
4921 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4923 triggered_spell_id
= 45429;
4928 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4929 // cast 45480 Light's Strength if Exalted by Aldor
4930 // cast 45428 Arcane Strike if Exalted by Scryers
4933 if(GetTypeId() != TYPEID_PLAYER
)
4936 // Get Aldor reputation rank
4937 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4940 triggered_spell_id
= 45480;
4943 // Get Scryers reputation rank
4944 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4946 triggered_spell_id
= 45428;
4951 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4952 // cast 45431 Arcane Insight if Exalted by Aldor
4953 // cast 45432 Light's Ward if Exalted by Scryers
4956 if(GetTypeId() != TYPEID_PLAYER
)
4959 // Get Aldor reputation rank
4960 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4963 triggered_spell_id
= 45432;
4966 // Get Scryers reputation rank
4967 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4970 triggered_spell_id
= 45431;
4975 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4976 // cast 45478 Light's Salvation if Exalted by Aldor
4977 // cast 45430 Arcane Surge if Exalted by Scryers
4980 if(GetTypeId() != TYPEID_PLAYER
)
4983 // Get Aldor reputation rank
4984 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4987 triggered_spell_id
= 45478;
4990 // Get Scryers reputation rank
4991 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4993 triggered_spell_id
= 45430;
5001 case SPELLFAMILY_MAGE
:
5004 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5006 if (getPowerType() != POWER_MANA
)
5010 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5012 triggered_spell_id
= 29442;
5015 // Master of Elements
5016 if (dummySpell
->SpellIconID
== 1920)
5022 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5023 if( basepoints0
<=0 )
5027 triggered_spell_id
= 29077;
5030 switch(dummySpell
->Id
)
5039 switch (dummySpell
->Id
)
5041 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5042 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5043 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5044 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5045 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5047 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5051 triggered_spell_id
= 12654;
5057 //last charge and crit
5058 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5060 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5061 return true; // charge counting (will removed)
5064 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5065 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5070 case SPELLFAMILY_WARRIOR
:
5073 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5075 // check attack comes not from behind
5076 if (!HasInArc(M_PI
, pVictim
))
5079 triggered_spell_id
= 22858;
5084 case SPELLFAMILY_WARLOCK
:
5086 // Seed of Corruption
5087 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5089 Modifier
* mod
= triggeredByAura
->GetModifier();
5090 // if damage is more than need or target die from damage deal finish spell
5091 // FIX ME: not triggered currently at death
5092 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5094 // remember guid before aura delete
5095 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5097 // Remove aura (before cast for prevent infinite loop handlers)
5098 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5100 // Cast finish spell (triggeredByAura already not exist!)
5101 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5102 return true; // no hidden cooldown
5106 mod
->m_amount
-=damage
;
5109 // Seed of Corruption (Mobs cast) - no die req
5110 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5112 Modifier
* mod
= triggeredByAura
->GetModifier();
5113 // if damage is more than need deal finish spell
5114 if( mod
->m_amount
<= damage
)
5116 // remember guid before aura delete
5117 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5119 // Remove aura (before cast for prevent infinite loop handlers)
5120 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5122 // Cast finish spell (triggeredByAura already not exist!)
5123 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5124 return true; // no hidden cooldown
5127 mod
->m_amount
-=damage
;
5130 switch(dummySpell
->Id
)
5137 triggered_spell_id
= 17941;
5146 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5148 triggered_spell_id
= 30294;
5151 // Shadowflame (Voidheart Raiment set bonus)
5154 triggered_spell_id
= 37379;
5157 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5165 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5166 triggered_spell_id
= 37382;
5169 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5172 triggered_spell_id
= 37378;
5178 case SPELLFAMILY_PRIEST
:
5181 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5183 if(!pVictim
|| !pVictim
->isAlive())
5186 // pVictim is caster of aura
5187 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5191 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5192 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5193 return true; // no hidden cooldown
5195 switch(dummySpell
->Id
)
5200 if(!pVictim
|| !pVictim
->isAlive())
5203 // pVictim is caster of aura
5204 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5208 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5209 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5210 return true; // no hidden cooldown
5212 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5215 // Shadow Word: Pain
5216 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5217 triggered_spell_id
= 40441;
5219 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5220 triggered_spell_id
= 40440;
5227 // Oracle Healing Bonus ("Garments of the Oracle" set)
5231 basepoints0
= int32(damage
* 10/100);
5233 triggered_spell_id
= 26170;
5236 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5239 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5243 basepoints0
= int32(damage
* 2 / 100);
5245 triggered_spell_id
= 39373;
5248 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5251 triggered_spell_id
= 28810;
5257 case SPELLFAMILY_DRUID
:
5259 switch(dummySpell
->Id
)
5261 // Healing Touch (Dreamwalker Raiment set)
5265 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5267 triggered_spell_id
= 28742;
5270 // Healing Touch Refund (Idol of Longevity trinket)
5274 triggered_spell_id
= 28848;
5277 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5282 triggered_spell_id
= 37238;
5285 // Druid Tier 6 Trinket
5291 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5293 triggered_spell_id
= 40445;
5297 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5299 triggered_spell_id
= 40446;
5302 // Mangle (cat/bear)
5303 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5305 triggered_spell_id
= 40452;
5311 if (!roll_chance_f(chance
))
5320 // Deadly Interrupt Effect
5321 triggered_spell_id
= 32747;
5327 case SPELLFAMILY_ROGUE
:
5329 switch(dummySpell
->Id
)
5331 // Deadly Throw Interrupt
5334 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5338 triggered_spell_id
= 32747;
5343 if( dummySpell
->SpellIconID
== 2116 )
5348 // only rogue's finishing moves (maybe need additional checks)
5349 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5350 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5354 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5355 if(basepoints0
<= 0)
5359 triggered_spell_id
= 31663;
5364 case SPELLFAMILY_HUNTER
:
5366 // Thrill of the Hunt
5367 if ( dummySpell
->SpellIconID
== 2236 )
5373 basepoints0
= procSpell
->manaCost
* 40/100;
5374 if(basepoints0
<= 0)
5378 triggered_spell_id
= 34720;
5383 case SPELLFAMILY_PALADIN
:
5385 // Seal of Righteousness - melee proc dummy
5386 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5388 if(GetTypeId() != TYPEID_PLAYER
)
5392 switch (triggeredByAura
->GetId())
5394 case 21084: spellId
= 25742; break; // Rank 1
5395 case 20287: spellId
= 25740; break; // Rank 2
5396 case 20288: spellId
= 25739; break; // Rank 3
5397 case 20289: spellId
= 25738; break; // Rank 4
5398 case 20290: spellId
= 25737; break; // Rank 5
5399 case 20291: spellId
= 25736; break; // Rank 6
5400 case 20292: spellId
= 25735; break; // Rank 7
5401 case 20293: spellId
= 25713; break; // Rank 8
5402 case 27155: spellId
= 27156; break; // Rank 9
5404 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5407 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5408 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5410 float damageBasePoints
;
5411 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5413 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5415 // one hand weapon/no weapon
5416 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5418 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5420 // apply damage bonuses manually
5421 if(damagePoint
>= 0)
5422 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5424 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5425 return true; // no hidden cooldown
5427 // Seal of Blood do damage trigger
5428 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5430 switch(triggeredByAura
->GetEffIndex())
5433 // prevent chain triggering
5434 if(procSpell
&& procSpell
->Id
==31893 )
5437 triggered_spell_id
= 31893;
5442 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5444 triggered_spell_id
= 32221;
5450 switch(dummySpell
->Id
)
5452 // Holy Power (Redemption Armor set)
5458 // Set class defined buff
5459 switch (pVictim
->getClass())
5465 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5469 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5473 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5476 triggered_spell_id
= 28790; // Increases the friendly target's armor
5486 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5489 triggered_spell_id
= 31803;
5496 // if healed by another unit (pVictim)
5501 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5503 triggered_spell_id
= 31786;
5506 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5514 // Flash of light/Holy light
5515 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5517 triggered_spell_id
= 40471;
5521 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5523 triggered_spell_id
= 40472;
5529 if (!roll_chance_f(chance
))
5537 case SPELLFAMILY_SHAMAN
:
5539 switch(dummySpell
->Id
)
5541 // Totemic Power (The Earthshatterer set)
5547 // Set class defined buff
5548 switch (pVictim
->getClass())
5554 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5558 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5562 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5565 triggered_spell_id
= 28827; // Increases the friendly target's armor
5572 // Lesser Healing Wave (Totem of Flowing Water Relic)
5576 triggered_spell_id
= 28850;
5579 // Windfury Weapon (Passive) 1-5 Ranks
5582 if(GetTypeId()!=TYPEID_PLAYER
)
5585 if(!castItem
|| !castItem
->IsEquipped())
5588 // custom cooldown processing case
5589 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5593 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5595 case 283: spellId
= 33757; break; //1 Rank
5596 case 284: spellId
= 33756; break; //2 Rank
5597 case 525: spellId
= 33755; break; //3 Rank
5598 case 1669:spellId
= 33754; break; //4 Rank
5599 case 2636:spellId
= 33727; break; //5 Rank
5602 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5603 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5608 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5609 if(!windfurySpellEntry
)
5611 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5615 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5618 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5620 // Value gained from additional AP
5621 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5622 triggered_spell_id
= 33750;
5627 // Value gained from additional AP
5628 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5629 triggered_spell_id
= 25504;
5632 // apply cooldown before cast to prevent processing itself
5634 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5637 for ( uint32 i
= 0; i
<2; ++i
)
5638 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5642 // Shaman Tier 6 Trinket
5649 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5651 triggered_spell_id
= 40465; // Lightning Bolt
5654 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5656 triggered_spell_id
= 40465; // Lesser Healing Wave
5659 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5661 triggered_spell_id
= 40466; // Stormstrike
5667 if (!roll_chance_f(chance
))
5676 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5678 if(GetTypeId() != TYPEID_PLAYER
)
5682 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5684 triggered_spell_id
= 379;
5687 // Lightning Overload
5688 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5690 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5693 // custom cooldown processing case
5694 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5698 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5699 switch (procSpell
->Id
)
5702 case 403: spellId
= 45284; break; // Rank 1
5703 case 529: spellId
= 45286; break; // Rank 2
5704 case 548: spellId
= 45287; break; // Rank 3
5705 case 915: spellId
= 45288; break; // Rank 4
5706 case 943: spellId
= 45289; break; // Rank 5
5707 case 6041: spellId
= 45290; break; // Rank 6
5708 case 10391: spellId
= 45291; break; // Rank 7
5709 case 10392: spellId
= 45292; break; // Rank 8
5710 case 15207: spellId
= 45293; break; // Rank 9
5711 case 15208: spellId
= 45294; break; // Rank 10
5712 case 25448: spellId
= 45295; break; // Rank 11
5713 case 25449: spellId
= 45296; break; // Rank 12
5715 case 421: spellId
= 45297; break; // Rank 1
5716 case 930: spellId
= 45298; break; // Rank 2
5717 case 2860: spellId
= 45299; break; // Rank 3
5718 case 10605: spellId
= 45300; break; // Rank 4
5719 case 25439: spellId
= 45301; break; // Rank 5
5720 case 25442: spellId
= 45302; break; // Rank 6
5722 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5725 // No thread generated mod
5726 SpellModifier
*mod
= new SpellModifier
;
5727 mod
->op
= SPELLMOD_THREAT
;
5729 mod
->type
= SPELLMOD_PCT
;
5730 mod
->spellId
= dummySpell
->Id
;
5732 mod
->lastAffected
= NULL
;
5733 mod
->mask
= 0x0000000000000003LL
;
5735 ((Player
*)this)->AddSpellMod(mod
, true);
5737 // Remove cooldown (Chain Lightning - have Category Recovery time)
5738 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5739 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5741 // Hmmm.. in most case spells already set half basepoints but...
5742 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5744 // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon.
5745 // So - no add changes :)
5746 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5748 ((Player
*)this)->AddSpellMod(mod
, false);
5750 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5751 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5761 // processed charge only counting case
5762 if(!triggered_spell_id
)
5765 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5769 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5774 if(!target
|| target
!=this && !target
->isAlive())
5777 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5781 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5783 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5785 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5786 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5791 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5793 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5795 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5796 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5798 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5799 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5800 int32 basepoints0
= 0;
5802 switch(auraSpellInfo
->SpellFamilyName
)
5804 case SPELLFAMILY_GENERIC
:
5806 switch(auraSpellInfo
->Id
)
5808 // Aegis of Preservation
5810 //Aegis Heal (instead non-existed triggered spell)
5811 triggered_spell_id
= 23781;
5814 // Elune's Touch (moonkin mana restore)
5817 // Elune's Touch (instead non-existed triggered spell)
5818 triggered_spell_id
= 33926;
5819 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5826 // only for cast with mana price
5827 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5829 break; // fall through to normal cast
5834 // at melee hit call std triggered spell
5835 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5836 break; // fall through to normal cast
5838 // Mark of Conquest - else (at range hit) called custom case
5839 triggered_spell_id
= 39557;
5845 return true; // nothing to do
5846 // Forgotten Knowledge (Blade of Wizardry)
5848 // only for harmful enemy targeted spell
5849 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5851 break; // fall through to normal cast
5852 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5855 // proc only at non-crit hits
5856 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5858 break; // fall through to normal cast
5860 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5866 //only periodic damage can trigger spell
5868 for(int j
= 0; j
< 3; ++j
)
5870 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5871 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5872 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5881 break; // fall through to normal cast
5883 // Evasive Maneuvers (Commendation of Kael'thas)
5886 // damage taken that reduces below 35% health
5887 // does NOT mean you must have been >= 35% before
5888 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5890 break; // fall through to normal cast
5894 switch(triggered_spell_id
)
5899 // applied only for main target
5900 if(!pVictim
|| pVictim
!= getVictim())
5903 // continue normal case
5906 // Shamanistic Rage triggered spell
5908 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5913 case SPELLFAMILY_MAGE
:
5915 switch(auraSpellInfo
->SpellIconID
)
5919 //Blazing Speed (instead non-existed triggered spell)
5920 triggered_spell_id
= 31643;
5924 switch(auraSpellInfo
->Id
)
5926 // Persistent Shield (Scarab Brooch)
5928 basepoints0
= int32(damage
* 0.15f
);
5933 case SPELLFAMILY_WARRIOR
:
5936 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5938 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5939 //and effect[1]==TriggerSpell
5940 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5942 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5945 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5946 break; // fall through to normal cast
5950 case SPELLFAMILY_WARLOCK
:
5953 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5955 // last case for Hellfire that damage caster also but don't must stun caster
5956 if( pVictim
== this )
5961 switch (triggeredByAura
->GetId())
5963 case 18096: chance
= 13.0f
; break;
5964 case 18073: chance
= 26.0f
; break;
5966 if (!roll_chance_f(chance
))
5969 // Pyroclasm (instead non-existed triggered spell)
5970 triggered_spell_id
= 18093;
5975 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5978 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5979 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5981 //Improved Drain Soul
5982 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5984 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5985 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5987 CastCustomSpell(this, 18371, &basepoints0
, NULL
, NULL
, true, castItem
, triggeredByAura
);
5991 // Not remove charge (aura removed on death in any cases)
5992 // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
5997 case SPELLFAMILY_PRIEST
:
6000 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6002 switch (triggeredByAura
->GetSpellProto()->Id
)
6004 case 27811: triggered_spell_id
= 27813; break;
6005 case 27815: triggered_spell_id
= 27817; break;
6006 case 27816: triggered_spell_id
= 27818; break;
6008 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6012 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6013 basepoints0
= heal_amount
/3;
6018 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
==7958)
6020 switch(triggeredByAura
->GetSpellProto()->Id
)
6023 triggered_spell_id
= 28377; break; // Rank 1
6025 triggered_spell_id
= 28378; break; // Rank 2
6027 triggered_spell_id
= 28379; break; // Rank 3
6029 triggered_spell_id
= 28380; break; // Rank 4
6031 triggered_spell_id
= 28381; break; // Rank 5
6033 triggered_spell_id
= 28382; break; // Rank 6
6035 triggered_spell_id
= 28385; break; // Rank 7
6037 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6045 case SPELLFAMILY_DRUID
:
6047 switch(auraSpellInfo
->Id
)
6049 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6052 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6054 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6055 triggered_spell_id
= 34299;
6058 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6065 triggered_spell_id
=37340; break;// Ursine Blessing
6067 triggered_spell_id
=37341; break;// Feline Blessing
6069 triggered_spell_id
=37342; break;// Slyvan Blessing
6071 triggered_spell_id
=37343; break;// Lunar Blessing
6073 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6084 case SPELLFAMILY_ROGUE
:
6086 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6088 switch(auraSpellInfo
->SpellIconID
)
6093 // skip non offhand attacks
6094 if(attackType
!=OFF_ATTACK
)
6096 break; // fall through to normal cast
6102 case SPELLFAMILY_PALADIN
:
6104 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6106 switch(auraSpellInfo
->Id
)
6108 // Lightning Capacitor
6111 // trinket ProcTriggerSpell but for safe checks for player
6112 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6115 if(((Player
*)this)->HasSpellCooldown(37657))
6119 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6120 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6121 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6125 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6126 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6127 if((*itr
)->GetId()==37658)
6130 // release at 3 aura in stack
6132 return true; // main triggered spell casted anyway
6134 RemoveAurasDueToSpell(37658);
6135 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6140 // Healing Trance (instead non-existed triggered spell)
6141 triggered_spell_id
= 37706;
6144 // HoTs on Heals (Fel Reaver's Piston trinket)
6147 // at direct heal effect
6148 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6151 // single proc at time
6152 AuraList
const& scAuras
= GetSingleCastAuras();
6153 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6154 if((*itr
)->GetId()==triggered_spell_id
)
6157 // positive cast at victim instead self
6162 switch(auraSpellInfo
->SpellIconID
)
6166 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6174 // procspell is triggered spell but we need mana cost of original casted spell
6175 uint32 originalSpellId
= procSpell
->Id
;
6178 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6180 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6182 switch(procSpell
->Id
)
6184 case 25914: originalSpellId
= 20473; break;
6185 case 25913: originalSpellId
= 20929; break;
6186 case 25903: originalSpellId
= 20930; break;
6187 case 27175: originalSpellId
= 27174; break;
6188 case 33074: originalSpellId
= 33072; break;
6190 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6196 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6199 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6203 // percent stored in effect 1 (class scripts) base points
6204 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6206 basepoints0
= originalSpell
->manaCost
*percent
/100;
6207 triggered_spell_id
= 20272;
6216 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6218 switch(auraSpellInfo
->SpellIconID
)
6220 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6223 if(!pVictim
|| !pVictim
->isAlive())
6226 switch(triggeredByAura
->GetSpellProto()->Id
)
6229 triggered_spell_id
= 20268; // Rank 1
6232 triggered_spell_id
= 20352; // Rank 2
6235 triggered_spell_id
= 20353; // Rank 3
6238 triggered_spell_id
= 27165; // Rank 4
6241 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6245 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6246 return true; // no hidden cooldown
6248 //Judgement of Light
6251 if(!pVictim
|| !pVictim
->isAlive())
6254 // overwrite non existing triggered spell call in spell.dbc
6255 switch(triggeredByAura
->GetSpellProto()->Id
)
6258 triggered_spell_id
= 20267; // Rank 1
6261 triggered_spell_id
= 20341; // Rank 2
6264 triggered_spell_id
= 20342; // Rank 3
6267 triggered_spell_id
= 20343; // Rank 4
6270 triggered_spell_id
= 27163; // Rank 5
6273 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6276 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6277 return true; // no hidden cooldown
6281 // custom check for proc spell
6282 switch(auraSpellInfo
->Id
)
6284 // Bonus Healing (item spell)
6287 if(!pVictim
|| !pVictim
->isAlive())
6290 // bonus if health < 50%
6291 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6294 // cast at target positive spell
6299 switch(triggered_spell_id
)
6303 // prevent chain of triggered spell from same triggered spell
6304 if(procSpell
&& procSpell
->Id
==20424)
6310 case SPELLFAMILY_SHAMAN
:
6312 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6314 switch(auraSpellInfo
->SpellIconID
)
6318 switch(auraSpellInfo
->Id
)
6320 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6322 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6323 triggered_spell_id
= 23552;
6327 case 23552: // Lightning Shield - trigger shield damage
6329 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6330 triggered_spell_id
= 27635;
6337 // Mana Surge (Shaman T1 bonus)
6343 basepoints0
= procSpell
->manaCost
* 35/100;
6344 triggered_spell_id
= 23571;
6351 if(GetTypeId()!=TYPEID_PLAYER
)
6354 // damage taken that reduces below 30% health
6355 // does NOT mean you must have been >= 30% before
6356 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6359 triggered_spell_id
= 31616;
6361 // need check cooldown now
6362 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6365 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6367 if(pVictim
&& pVictim
->isAlive())
6368 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6374 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6375 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
==7358)
6382 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
==37)
6384 // overwrite non existing triggered spell call in spell.dbc
6385 switch(triggeredByAura
->GetSpellProto()->Id
)
6388 triggered_spell_id
= 26364; break; // Rank 1
6390 triggered_spell_id
= 26365; break; // Rank 2
6392 triggered_spell_id
= 26366; break; // Rank 3
6394 triggered_spell_id
= 26367; break; // Rank 4
6396 triggered_spell_id
= 26369; break; // Rank 5
6398 triggered_spell_id
= 26370; break; // Rank 6
6400 triggered_spell_id
= 26363; break; // Rank 7
6402 triggered_spell_id
= 26371; break; // Rank 8
6404 triggered_spell_id
= 26372; break; // Rank 9
6406 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6417 // standard non-dummy case
6418 if(!triggered_spell_id
)
6420 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6424 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6428 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6432 // not allow proc extra attack spell at extra attack
6433 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6436 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6440 if(!target
|| target
!=this && !target
->isAlive())
6444 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6446 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6448 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6449 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6454 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6456 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6458 if(!pVictim
|| !pVictim
->isAlive())
6461 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6462 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6464 uint32 triggered_spell_id
= 0;
6468 case 836: // Improved Blizzard (Rank 1)
6470 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6472 triggered_spell_id
= 12484;
6475 case 988: // Improved Blizzard (Rank 2)
6477 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6479 triggered_spell_id
= 12485;
6482 case 989: // Improved Blizzard (Rank 3)
6484 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6486 triggered_spell_id
= 12486;
6489 case 4086: // Improved Mend Pet (Rank 1)
6490 case 4087: // Improved Mend Pet (Rank 2)
6492 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6493 if(!roll_chance_i(chance
))
6496 triggered_spell_id
= 24406;
6499 case 4533: // Dreamwalker Raiment 2 pieces bonus
6502 if (!roll_chance_i(50))
6505 switch (pVictim
->getPowerType())
6507 case POWER_MANA
: triggered_spell_id
= 28722; break;
6508 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6509 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6515 case 4537: // Dreamwalker Raiment 6 pieces bonus
6516 triggered_spell_id
= 28750; // Blessing of the Claw
6518 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6519 triggered_spell_id
= 37445; // Mana Surge
6524 if(!triggered_spell_id
)
6527 // standard non-dummy case
6528 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6532 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6536 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6539 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6541 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6542 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6547 void Unit::setPowerType(Powers new_powertype
)
6549 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6551 if(GetTypeId() == TYPEID_PLAYER
)
6553 if(((Player
*)this)->GetGroup())
6554 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6556 else if(((Creature
*)this)->isPet())
6558 Pet
*pet
= ((Pet
*)this);
6559 if(pet
->isControlled())
6561 Unit
*owner
= GetOwner();
6562 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6563 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6567 switch(new_powertype
)
6573 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6574 SetPower( POWER_RAGE
,0);
6577 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6578 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6581 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6582 SetPower( POWER_ENERGY
,0);
6584 case POWER_HAPPINESS
:
6585 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6586 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6591 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6593 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6596 static uint64 guid
= 0; // prevent repeating spam same faction problem
6598 if(GetGUID() != guid
)
6600 if(GetTypeId() == TYPEID_PLAYER
)
6601 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6603 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6610 bool Unit::IsHostileTo(Unit
const* unit
) const
6612 // always non-hostile to self
6616 // always non-hostile to GM in GM mode
6617 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6620 // always hostile to enemy
6621 if(getVictim()==unit
|| unit
->getVictim()==this)
6624 // test pet/charm masters instead pers/charmeds
6625 Unit
const* testerOwner
= GetCharmerOrOwner();
6626 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6628 // always hostile to owner's enemy
6629 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6632 // always hostile to enemy owner
6633 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6636 // always hostile to owner of owner's enemy
6637 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6640 Unit
const* tester
= testerOwner
? testerOwner
: this;
6641 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6643 // always non-hostile to target with common owner, or to owner/pet
6647 // special cases (Duel, etc)
6648 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6650 Player
const* pTester
= (Player
const*)tester
;
6651 Player
const* pTarget
= (Player
const*)target
;
6654 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6658 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6662 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6666 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6670 // Green/Blue (can't attack)
6671 if(pTester
->GetTeam()==pTarget
->GetTeam())
6674 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6675 return pTester
->IsPvP() && pTarget
->IsPvP();
6678 // faction base cases
6679 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6680 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6681 if(!tester_faction
|| !target_faction
)
6684 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6687 // PvC forced reaction and reputation case
6688 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6691 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6692 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6693 return forceItr
->second
<= REP_HOSTILE
;
6695 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6696 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6697 if(raw_target_faction
->reputationListID
>=0)
6698 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6699 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6701 // CvP forced reaction and reputation case
6702 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6705 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6706 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6707 return forceItr
->second
<= REP_HOSTILE
;
6709 // apply reputation state
6710 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6711 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6712 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6715 // common faction based case (CvC,PvC,CvP)
6716 return tester_faction
->IsHostileTo(*target_faction
);
6719 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6721 // always friendly to self
6725 // always friendly to GM in GM mode
6726 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6729 // always non-friendly to enemy
6730 if(getVictim()==unit
|| unit
->getVictim()==this)
6733 // test pet/charm masters instead pers/charmeds
6734 Unit
const* testerOwner
= GetCharmerOrOwner();
6735 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6737 // always non-friendly to owner's enemy
6738 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6741 // always non-friendly to enemy owner
6742 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6745 // always non-friendly to owner of owner's enemy
6746 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6749 Unit
const* tester
= testerOwner
? testerOwner
: this;
6750 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6752 // always friendly to target with common owner, or to owner/pet
6756 // special cases (Duel)
6757 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6759 Player
const* pTester
= (Player
const*)tester
;
6760 Player
const* pTarget
= (Player
const*)target
;
6763 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6767 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6771 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6775 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6779 // Green/Blue (non-attackable)
6780 if(pTester
->GetTeam()==pTarget
->GetTeam())
6783 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6784 return !pTarget
->IsPvP();
6787 // faction base cases
6788 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6789 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6790 if(!tester_faction
|| !target_faction
)
6793 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6796 // PvC forced reaction and reputation case
6797 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6800 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6801 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6802 return forceItr
->second
>= REP_FRIENDLY
;
6804 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6805 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6806 if(raw_target_faction
->reputationListID
>=0)
6807 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6808 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6810 // CvP forced reaction and reputation case
6811 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6814 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6815 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6816 return forceItr
->second
>= REP_FRIENDLY
;
6818 // apply reputation state
6819 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6820 if(raw_tester_faction
->reputationListID
>=0 )
6821 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6824 // common faction based case (CvC,PvC,CvP)
6825 return tester_faction
->IsFriendlyTo(*target_faction
);
6828 bool Unit::IsHostileToPlayers() const
6830 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6834 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6835 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6838 return my_faction
->IsHostileToPlayers();
6841 bool Unit::IsNeutralToAll() const
6843 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6847 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6848 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6851 return my_faction
->IsNeutralToAll();
6854 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6856 if(!victim
|| victim
== this)
6859 // dead units can neither attack nor be attacked
6860 if(!isAlive() || !victim
->isAlive())
6863 // player cannot attack in mount state
6864 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6867 // nobody can attack GM in GM-mode
6868 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6870 if(((Player
*)victim
)->isGameMaster())
6875 if(((Creature
*)victim
)->IsInEvadeMode())
6879 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6880 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6881 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6885 if (m_attacking
== victim
)
6887 // switch to melee attack from ranged/magic
6888 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6890 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6891 SendAttackStart(victim
);
6900 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6903 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6904 m_attacking
= victim
;
6905 m_attacking
->_addAttacker(this);
6907 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6908 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6910 if(GetTypeId()==TYPEID_UNIT
)
6912 WorldPacket
data(SMSG_AI_REACTION
, 12);
6913 data
<< uint64(GetGUID());
6914 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6915 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6917 ((Creature
*)this)->CallAssistance();
6918 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6921 // delay offhand weapon attack to next attack time
6922 if(haveOffhandWeapon())
6923 resetAttackTimer(OFF_ATTACK
);
6926 SendAttackStart(victim
);
6931 bool Unit::AttackStop()
6936 Unit
* victim
= m_attacking
;
6938 m_attacking
->_removeAttacker(this);
6942 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6944 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6946 InterruptSpell(CURRENT_MELEE_SPELL
);
6948 if( GetTypeId()==TYPEID_UNIT
)
6950 // reset call assistance
6951 ((Creature
*)this)->SetNoCallAssistance(false);
6954 SendAttackStop(victim
);
6959 void Unit::CombatStop(bool cast
)
6961 if(cast
& IsNonMeleeSpellCasted(false))
6962 InterruptNonMeleeSpells(false);
6965 RemoveAllAttackers();
6966 if( GetTypeId()==TYPEID_PLAYER
)
6967 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6971 void Unit::CombatStopWithPets(bool cast
)
6974 if(Pet
* pet
= GetPet())
6975 pet
->CombatStop(cast
);
6976 if(Unit
* charm
= GetCharm())
6977 charm
->CombatStop(cast
);
6978 if(GetTypeId()==TYPEID_PLAYER
)
6980 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6981 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6982 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6983 guardian
->CombatStop(cast
);
6987 bool Unit::isAttackingPlayer() const
6989 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
6992 Pet
* pet
= GetPet();
6993 if(pet
&& pet
->isAttackingPlayer())
6996 Unit
* charmed
= GetCharm();
6997 if(charmed
&& charmed
->isAttackingPlayer())
7000 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7004 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7005 if(totem
&& totem
->isAttackingPlayer())
7013 void Unit::RemoveAllAttackers()
7015 while (!m_attackers
.empty())
7017 AttackerSet::iterator iter
= m_attackers
.begin();
7018 if(!(*iter
)->AttackStop())
7020 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
7021 m_attackers
.erase(iter
);
7026 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7030 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7032 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7033 if(GetTypeId() == TYPEID_PLAYER
)
7035 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7036 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7038 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7039 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7040 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7041 if (spellInfo
->CasterAuraState
== flag
)
7042 CastSpell(this, itr
->first
, true, NULL
);
7049 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7051 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7052 Unit::AuraMap
& tAuras
= GetAuras();
7053 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7055 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7056 if (spellProto
->CasterAuraState
== flag
)
7058 // exceptions (applied at state but not removed at state change)
7060 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7075 Unit
*Unit::GetOwner() const
7077 uint64 ownerid
= GetOwnerGUID();
7080 return ObjectAccessor::GetUnit(*this, ownerid
);
7083 Unit
*Unit::GetCharmer() const
7085 if(uint64 charmerid
= GetCharmerGUID())
7086 return ObjectAccessor::GetUnit(*this, charmerid
);
7090 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7092 uint64 guid
= GetCharmerOrOwnerGUID();
7093 if(IS_PLAYER_GUID(guid
))
7094 return ObjectAccessor::GetPlayer(*this, guid
);
7096 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7099 Pet
* Unit::GetPet() const
7101 if(uint64 pet_guid
= GetPetGUID())
7103 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7106 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7107 const_cast<Unit
*>(this)->SetPet(0);
7113 Unit
* Unit::GetCharm() const
7115 if(uint64 charm_guid
= GetCharmGUID())
7117 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7120 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7121 const_cast<Unit
*>(this)->SetCharm(0);
7127 void Unit::SetPet(Pet
* pet
)
7129 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7131 // FIXME: hack, speed must be set only at follow
7133 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7134 pet
->SetSpeed(UnitMoveType(i
), m_speed_rate
[i
], true);
7137 void Unit::SetCharm(Unit
* pet
)
7139 SetUInt64Value(UNIT_FIELD_CHARM
, pet
? pet
->GetGUID() : 0);
7142 void Unit::UnsummonAllTotems()
7144 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7149 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7150 if (OldTotem
&& OldTotem
->isTotem())
7151 ((Totem
*)OldTotem
)->UnSummon();
7155 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7158 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7159 data
.append(pVictim
->GetPackGUID());
7160 data
.append(GetPackGUID());
7161 data
<< uint32(SpellID
);
7162 data
<< uint32(Damage
);
7163 data
<< uint8(critical
? 1 : 0);
7164 data
<< uint8(0); // unused in client?
7165 SendMessageToSet(&data
, true);
7168 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7170 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7171 data
.append(pVictim
->GetPackGUID());
7172 data
.append(GetPackGUID());
7173 data
<< uint32(SpellID
);
7174 data
<< uint32(powertype
);
7175 data
<< uint32(Damage
);
7176 SendMessageToSet(&data
, true);
7179 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7181 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7184 int32 BonusDamage
= 0;
7185 if( GetTypeId()==TYPEID_UNIT
)
7187 // Pets just add their bonus damage to their spell damage
7188 // note that their spell damage is just gain of their own auras
7189 if (((Creature
*)this)->isPet())
7191 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7193 // For totems get damage bonus from owner (statue isn't totem in fact)
7194 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7196 if(Unit
* owner
= GetOwner())
7197 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7202 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7204 // Taken/Done fixed damage bonus auras
7205 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7206 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7208 // Damage over Time spells bonus calculation
7209 float DotFactor
= 1.0f
;
7210 if(damagetype
== DOT
)
7212 int32 DotDuration
= GetSpellDuration(spellProto
);
7216 if(DotDuration
> 30000) DotDuration
= 30000;
7217 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7219 for(int j
= 0; j
< 3; j
++)
7221 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7222 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7223 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7230 if(spellProto
->EffectAmplitude
[x
] != 0)
7231 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7234 DoneAdvertisedBenefit
/= DotTicks
;
7235 TakenAdvertisedBenefit
/= DotTicks
;
7240 // Taken/Done total percent damage auras
7241 float DoneTotalMod
= 1.0f
;
7242 float TakenTotalMod
= 1.0f
;
7245 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7246 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7248 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7249 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7250 // -1 == any item class (not wand then)
7251 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7252 // 0 == any inventory type (not wand then)
7254 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7258 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7259 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7260 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7261 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7262 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7265 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7266 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7267 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7268 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7270 // .. taken pct: scripted (increases damage of * against targets *)
7271 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7272 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7274 switch((*i
)->GetModifier()->m_miscvalue
)
7277 case 4920: case 4919:
7278 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7279 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7283 // .. taken pct: dummy auras
7284 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7285 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7287 switch((*i
)->GetSpellProto()->SpellIconID
)
7291 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7293 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7295 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7296 if (mod
< (*i
)->GetModifier()->m_amount
)
7297 mod
= (*i
)->GetModifier()->m_amount
;
7298 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7303 for(int j
=0;j
<3;j
++)
7305 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7307 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7315 // Distribute Damage over multiple effects, reduce by AoE
7316 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7318 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7319 for(int j
= 0; j
< 3; ++j
)
7321 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7322 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7329 switch(spellProto
->SpellFamilyName
)
7331 case SPELLFAMILY_MAGE
:
7332 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7333 if(spellProto
->Id
==12654)
7338 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7340 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7341 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7342 TakenTotalMod
*= 3.0f
;
7344 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7345 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7347 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7348 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7350 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7351 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7354 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7357 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7361 // Arcane Missiles triggered spell
7362 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7366 // Blizzard triggered spell
7367 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7372 case SPELLFAMILY_WARLOCK
:
7374 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7376 CastingTime
= 2800; // 80% from +shadow damage
7377 DoneTotalMod
= 1.0f
;
7378 TakenTotalMod
= 1.0f
;
7381 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7383 CastingTime
= 3360; // 96% from +shadow damage
7384 DoneTotalMod
= 1.0f
;
7385 TakenTotalMod
= 1.0f
;
7387 // Soul Fire - 115% of Fire Damage
7388 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7392 // Curse of Agony - 120% of Shadow Damage
7393 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7397 // Drain Mana - 0% of Shadow Damage
7398 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7402 // Drain Soul 214.3%
7403 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7408 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7410 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7412 // Unstable Affliction - 180%
7413 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7418 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7423 case SPELLFAMILY_PALADIN
:
7424 // Consecration - 95% of Holy Damage
7425 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7430 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7431 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7433 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7434 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7436 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7437 CastingTime
= uint32(wspeed
*3500*0.102f
);
7439 CastingTime
= uint32(wspeed
*3500*0.098f
);
7441 // Judgement of Righteousness - 73%
7442 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7446 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7447 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7452 // Holy shield - 5% of Holy Damage
7453 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7457 // Blessing of Sanctuary - 0%
7458 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7462 // Seal of Righteousness trigger - already computed for parent spell
7463 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7468 case SPELLFAMILY_SHAMAN
:
7470 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7472 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7473 CastingTime
= 749; // ignore CastingTime and use as modifier
7474 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7475 CastingTime
= 280; // ignore CastingTime and use as modifier
7476 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7477 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7479 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7480 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7481 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7483 case SPELLFAMILY_PRIEST
:
7484 // Mana Burn - 0% of Shadow Damage
7485 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7489 // Mind Flay - 59% of Shadow Damage
7490 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7494 // Holy Fire - 86.71%, DoT - 16.5%
7495 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7497 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7498 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7500 // Shadowguard - 28% per charge
7501 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7505 // Touch of Weakeness - 10%
7506 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7510 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7511 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7516 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7521 case SPELLFAMILY_DRUID
:
7522 // Hurricane triggered spell
7523 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7528 case SPELLFAMILY_WARRIOR
:
7529 case SPELLFAMILY_HUNTER
:
7530 case SPELLFAMILY_ROGUE
:
7537 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7539 // Spellmod SpellDamage
7540 float SpellModSpellDamage
= 100.0f
;
7542 if(Player
* modOwner
= GetSpellModOwner())
7543 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7545 SpellModSpellDamage
/= 100.0f
;
7547 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7548 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7550 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7552 // Add flat bonus from spell damage versus
7553 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7555 // apply spellmod to Done damage
7556 if(Player
* modOwner
= GetSpellModOwner())
7557 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7559 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7561 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7562 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7564 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7567 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7569 int32 DoneAdvertisedBenefit
= 0;
7572 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7573 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7574 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7575 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7576 // -1 == any item class (not wand then)
7577 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7578 // 0 == any inventory type (not wand then)
7579 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7581 if (GetTypeId() == TYPEID_PLAYER
)
7583 // Damage bonus from stats
7584 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7585 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7587 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7589 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7590 uint8 eff
= (*i
)->GetEffIndex();
7592 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7593 Stats usedStat
= STAT_INTELLECT
;
7594 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7595 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7597 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7600 // ... and attack power
7601 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7602 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7603 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7604 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7607 return DoneAdvertisedBenefit
;
7610 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7612 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7614 int32 TakenAdvertisedBenefit
= 0;
7615 // ..done (for creature type by mask) in taken
7616 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7617 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7618 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7619 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7622 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7623 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7624 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7625 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7627 return TakenAdvertisedBenefit
;
7630 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7632 // not critting spell
7633 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7636 float crit_chance
= 0.0f
;
7637 switch(spellProto
->DmgClass
)
7639 case SPELL_DAMAGE_CLASS_NONE
:
7641 case SPELL_DAMAGE_CLASS_MAGIC
:
7643 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7645 // For other schools
7646 else if (GetTypeId() == TYPEID_PLAYER
)
7647 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7650 crit_chance
= m_baseSpellCritChance
;
7651 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7654 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7656 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7657 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7658 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7659 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7660 // Modify by player victim resilience
7661 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7662 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7663 // scripted (increase crit chance ... against ... target by x%
7664 if(pVictim
->isFrozen()) // Shatter
7666 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7667 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7669 switch((*i
)->GetModifier()->m_miscvalue
)
7671 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7672 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7673 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7674 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7675 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7682 case SPELL_DAMAGE_CLASS_MELEE
:
7683 case SPELL_DAMAGE_CLASS_RANGED
:
7687 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7688 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7689 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7697 // only players use intelligence for critical chance computations
7698 if(Player
* modOwner
= GetSpellModOwner())
7699 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7701 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7702 if (roll_chance_f(crit_chance
))
7707 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7709 // Calculate critical bonus
7711 switch(spellProto
->DmgClass
)
7713 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7714 case SPELL_DAMAGE_CLASS_RANGED
:
7715 // TODO: write here full calculation for melee/ranged spells
7716 crit_bonus
= damage
;
7719 crit_bonus
= damage
/ 2; // for spells is 50%
7723 // adds additional damage to crit_bonus (from talents)
7724 if(Player
* modOwner
= GetSpellModOwner())
7725 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7729 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7730 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7734 damage
+= crit_bonus
;
7739 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7741 // For totems get healing bonus from owner (statue isn't totem in fact)
7742 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7743 if(Unit
* owner
= GetOwner())
7744 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7748 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7749 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7750 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7751 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7754 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7755 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7758 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7760 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7761 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7763 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7764 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7766 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
7769 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7770 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7772 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7773 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7778 float ActualBenefit
= 0.0f
;
7780 if (AdvertisedBenefit
!= 0)
7782 // Healing over Time spells
7783 float DotFactor
= 1.0f
;
7784 if(damagetype
== DOT
)
7786 int32 DotDuration
= GetSpellDuration(spellProto
);
7790 if(DotDuration
> 30000) DotDuration
= 30000;
7791 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7793 for(int j
= 0; j
< 3; j
++)
7795 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7796 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7797 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7804 if(spellProto
->EffectAmplitude
[x
] != 0)
7805 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7807 AdvertisedBenefit
/= DotTicks
;
7811 // distribute healing to all effects, reduce AoE damage
7812 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7814 // 0% bonus for damage and healing spells for leech spells from healing bonus
7815 for(int j
= 0; j
< 3; ++j
)
7817 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7818 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7826 switch (spellProto
->SpellFamilyName
)
7828 case SPELLFAMILY_SHAMAN
:
7829 // Healing stream from totem (add 6% per tick from hill bonus owner)
7830 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7832 // Earth Shield 30% per charge
7833 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7836 case SPELLFAMILY_DRUID
:
7838 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7840 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7841 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7843 // Tranquility triggered spell
7844 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7847 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7850 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7852 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7853 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7856 case SPELLFAMILY_PRIEST
:
7858 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7861 case SPELLFAMILY_PALADIN
:
7862 // Seal and Judgement of Light
7863 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7866 case SPELLFAMILY_WARRIOR
:
7867 case SPELLFAMILY_ROGUE
:
7868 case SPELLFAMILY_HUNTER
:
7873 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7875 // Spellmod SpellDamage
7876 float SpellModSpellDamage
= 100.0f
;
7878 if(Player
* modOwner
= GetSpellModOwner())
7879 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7881 SpellModSpellDamage
/= 100.0f
;
7883 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7886 // use float as more appropriate for negative values and percent applying
7887 float heal
= healamount
+ ActualBenefit
;
7889 // TODO: check for ALL/SPELLS type
7890 // Healing done percent
7891 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7892 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7893 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7895 // apply spellmod to Done amount
7896 if(Player
* modOwner
= GetSpellModOwner())
7897 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7899 // Healing Wave cast
7900 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7902 // Search for Healing Way on Victim (stack up to 3 time)
7904 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7905 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7906 if((*itr
)->GetId() == 29203)
7907 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7910 heal
= heal
* (100 + pctMod
) / 100;
7913 // Healing taken percent
7914 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7916 heal
*= (100.0f
+ minval
) / 100.0f
;
7918 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7920 heal
*= (100.0f
+ maxval
) / 100.0f
;
7922 if (heal
< 0) heal
= 0;
7924 return uint32(heal
);
7927 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7929 int32 AdvertisedBenefit
= 0;
7931 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7932 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7933 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7934 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7936 // Healing bonus of spirit, intellect and strength
7937 if (GetTypeId() == TYPEID_PLAYER
)
7939 // Healing bonus from stats
7940 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7941 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7943 // stat used dependent from misc value (stat index)
7944 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7945 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7948 // ... and attack power
7949 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7950 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7951 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7952 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7954 return AdvertisedBenefit
;
7957 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7959 int32 AdvertisedBenefit
= 0;
7960 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7961 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7962 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7963 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7964 return AdvertisedBenefit
;
7967 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7969 // no charges dependent checks
7970 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7971 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7972 if(itr
->type
& shoolMask
)
7975 // charges dependent checks
7976 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7977 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7979 if(itr
->type
& shoolMask
)
7983 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7984 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
7986 if((*auraItr
)->GetId()==itr
->spellId
)
7988 if((*auraItr
)->m_procCharges
> 0)
7990 --(*auraItr
)->m_procCharges
;
7991 if((*auraItr
)->m_procCharges
==0)
7992 RemoveAurasDueToSpell(itr
->spellId
);
8005 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8012 //FIX ME this hack: don't get feared if stunned
8013 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8015 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8019 // not have spells with charges currently
8020 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8021 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8022 if(itr
->type
== spellInfo
->Dispel
)
8025 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
) && // unaffected by school immunity
8026 !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)) // can remove immune (by dispell or immune it)
8028 // not have spells with charges currently
8029 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8030 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8031 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8032 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8036 // charges dependent checks
8038 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8039 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8041 if(itr
->type
== spellInfo
->Mechanic
)
8045 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8046 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8048 if((*auraItr
)->GetId()==itr
->spellId
)
8050 if((*auraItr
)->m_procCharges
> 0)
8052 --(*auraItr
)->m_procCharges
;
8053 if((*auraItr
)->m_procCharges
==0)
8054 RemoveAurasDueToSpell(itr
->spellId
);
8067 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8069 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8070 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8071 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8072 if(itr
->type
== effect
)
8075 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8076 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8077 if(itr
->type
== mechanic
)
8083 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8088 uint32 family
= spellInfo
->SpellFamilyName
;
8089 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8091 if((family
== 5 && flags
== 256) || //Searing Pain
8092 (family
== 6 && flags
== 8192) || //Mind Blast
8093 (family
== 11 && flags
== 1048576)) //Earth Shock
8099 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8107 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8109 // Taken/Done fixed damage bonus auras
8110 int32 DoneFlatBenefit
= 0;
8111 int32 TakenFlatBenefit
= 0;
8113 // ..done (for creature type by mask) in taken
8114 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8115 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8116 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8117 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8120 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8122 // ..done (base at attack power for marked target and base at attack power for creature type)
8124 if(attType
== RANGED_ATTACK
)
8126 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8128 // ..done (base at attack power and creature type)
8129 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8130 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8131 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8132 APbonus
+= (*i
)->GetModifier()->m_amount
;
8136 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8138 // ..done (base at attack power and creature type)
8139 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8140 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8141 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8142 APbonus
+= (*i
)->GetModifier()->m_amount
;
8145 if (APbonus
!=0) // Can be negative
8147 bool normalized
= false;
8150 for (uint8 i
= 0; i
<3;i
++)
8152 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8160 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8164 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8165 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8166 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8167 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8169 if(attType
!=RANGED_ATTACK
)
8170 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8172 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8174 // Done/Taken total percent damage auras
8175 float DoneTotalMod
= 1;
8176 float TakenTotalMod
= 1;
8179 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8180 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8182 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8183 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8184 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8185 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8188 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8189 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8190 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8191 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8193 // .. taken pct: dummy auras
8194 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8195 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8197 switch((*i
)->GetSpellProto()->SpellIconID
)
8201 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8203 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8205 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8206 if (mod
< (*i
)->GetModifier()->m_amount
)
8207 mod
= (*i
)->GetModifier()->m_amount
;
8208 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8213 if(spellProto
==NULL
)
8215 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8216 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8217 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8222 // .. taken pct: class scripts
8223 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8224 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8226 switch((*i
)->GetMiscValue())
8228 case 6427: case 6428: // Dirty Deeds
8229 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8231 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8232 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8234 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8238 // effect 0 have expected value but in negative state
8239 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8245 if(attType
!= RANGED_ATTACK
)
8247 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8248 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8249 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8253 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8254 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8255 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8258 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8260 // apply spellmod to Done damage
8263 if(Player
* modOwner
= GetSpellModOwner())
8264 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8267 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8269 // bonus result can be negative
8270 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8273 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8277 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8280 if(itr
->type
== type
)
8282 m_spellImmune
[op
].erase(itr
);
8283 next
= m_spellImmune
[op
].begin();
8287 Immune
.spellId
= spellId
;
8289 m_spellImmune
[op
].push_back(Immune
);
8293 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8295 if(itr
->spellId
== spellId
)
8297 m_spellImmune
[op
].erase(itr
);
8305 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8307 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8309 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8310 RemoveAurasWithDispelType(type
);
8313 float Unit::GetWeaponProcChance() const
8315 // normalized proc chance for weapon attack speed
8317 if(isAttackReady(BASE_ATTACK
))
8318 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8319 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8320 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8324 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8326 // proc per minute chance calculation
8327 if (PPM
<= 0) return 0.0f
;
8328 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8332 void Unit::Mount(uint32 mount
)
8337 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8339 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8341 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8344 if(GetTypeId() == TYPEID_PLAYER
)
8346 Pet
* pet
= GetPet();
8349 if(pet
->isControlled())
8351 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8352 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8355 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8358 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8362 void Unit::Unmount()
8367 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8369 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8370 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8372 // only resummon old pet if the player is already added to a map
8373 // this prevents adding a pet to a not created map which would otherwise cause a crash
8374 // (it could probably happen when logging in after a previous crash)
8375 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8377 Pet
* NewPet
= new Pet
;
8378 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8381 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8385 void Unit::SetInCombatWith(Unit
* enemy
)
8387 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8390 SetInCombatState(true);
8395 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8397 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8398 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8400 SetInCombatState(true);
8404 SetInCombatState(false);
8407 void Unit::SetInCombatState(bool PvP
)
8409 // only alive units can be in combat
8414 m_CombatTimer
= 5000;
8415 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8417 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8418 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8421 void Unit::ClearInCombat()
8424 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8426 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8427 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8429 // Player's state will be cleared in Player::UpdateContestedPvP
8430 if(GetTypeId()!=TYPEID_PLAYER
)
8431 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8434 bool Unit::isTargetableForAttack() const
8436 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8439 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8442 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8445 int32
Unit::ModifyHealth(int32 dVal
)
8452 int32 curHealth
= (int32
)GetHealth();
8454 int32 val
= dVal
+ curHealth
;
8461 int32 maxHealth
= (int32
)GetMaxHealth();
8466 gain
= val
- curHealth
;
8468 else if(curHealth
!= maxHealth
)
8470 SetHealth(maxHealth
);
8471 gain
= maxHealth
- curHealth
;
8477 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8484 int32 curPower
= (int32
)GetPower(power
);
8486 int32 val
= dVal
+ curPower
;
8493 int32 maxPower
= (int32
)GetMaxPower(power
);
8497 SetPower(power
,val
);
8498 gain
= val
- curPower
;
8500 else if(curPower
!= maxPower
)
8502 SetPower(power
,maxPower
);
8503 gain
= maxPower
- curPower
;
8509 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
, bool is3dDistance
) const
8514 // Always can see self
8518 // player visible for other player if not logout and at same transport
8519 // including case when player is out of world
8520 bool at_same_transport
=
8521 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8522 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8523 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8524 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8527 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8530 // forbidden to seen (at GM respawn command)
8531 if(m_Visibility
==VISIBILITY_RESPAWN
)
8534 // always seen by owner
8535 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8538 // Grid dead/alive checks
8539 if( u
->GetTypeId()==TYPEID_PLAYER
)
8541 // non visible at grid for any stealth state
8542 if(!IsVisibleInGridForPlayer((Player
*)u
))
8545 // if player is dead then he can't detect anyone in any cases
8551 // all dead creatures/players not visible for any creatures
8552 if(!u
->isAlive() || !isAlive())
8556 // different visible distance checks
8557 if(u
->isInFlight()) // what see player in flight
8559 // use object grey distance for all (only see objects any way)
8560 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8563 else if(!isAlive()) // distance for show body
8565 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8568 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8570 if(u
->GetTypeId()==TYPEID_PLAYER
)
8572 // Players far than max visible distance for player or not in our map are not visible too
8573 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8578 // Units far than max visible distance for creature or not in our map are not visible too
8579 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8583 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8585 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8586 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8589 else // distance for show creature
8591 // Units far than max visible distance for creature or not in our map are not visible too
8592 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8596 // Visible units, always are visible for all units, except for units under invisibility
8597 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8600 // GMs see any players, not higher GMs and all units
8601 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8603 if(GetTypeId() == TYPEID_PLAYER
)
8604 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8609 // non faction visibility non-breakable for non-GMs
8610 if (m_Visibility
== VISIBILITY_OFF
)
8614 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8616 // detectable invisibility case
8618 // Invisible units, always are visible for units under same invisibility type
8619 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8620 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8621 u
->canDetectInvisibilityOf(this) ||
8622 // Units that can detect invisibility always are visible for units that can be detected
8623 canDetectInvisibilityOf(u
) ))
8628 // special cases for always overwrite invisibility/stealth
8629 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8632 if (!u
->IsHostileTo(this))
8634 // 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)
8635 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8637 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8640 // else apply same rules as for hostile case (detecting check for stealth)
8646 // Hunter mark functionality
8647 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8648 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8649 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8652 // else apply detecting check for stealth
8655 // none other cases for detect invisibility, so invisible
8659 // else apply stealth detecting check
8662 // unit got in stealth in this moment and must ignore old detected state
8663 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8666 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8667 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8670 // NOW ONLY STEALTH CASE
8672 // stealth and detected and visible for some seconds
8673 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8676 //if in non-detect mode then invisible for unit
8682 // If is attacked then stealth is lost, some creature can use stealth too
8683 if( !getAttackers().empty() )
8686 // If there is collision rogue is seen regardless of level difference
8687 // TODO: check sizes in DB
8688 float distance
= GetDistance(u
);
8689 if (distance
< 0.24f
)
8692 //If a mob or player is stunned he will not be able to detect stealth
8693 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8696 // Creature can detect target only in aggro radius
8697 if(u
->GetTypeId() != TYPEID_PLAYER
)
8699 //Always invisible from back and out of aggro range
8700 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8706 //Always invisible from back
8707 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8712 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8713 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8715 //Calculation if target is in front
8717 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8718 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8720 //Visible distance is modified by
8721 //-Level Diff (every level diff = 1.0f in visible distance)
8722 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8724 //This allows to check talent tree and will add addition stealth dependent on used points)
8725 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8729 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8730 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8731 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8733 if(distance
> visibleDistance
)
8737 // Now check is target visible with LoS
8739 u
->GetPosition(ox
,oy
,oz
);
8740 return IsWithinLOS(ox
,oy
,oz
);
8743 void Unit::SetVisibility(UnitVisibility x
)
8751 if(GetTypeId()==TYPEID_PLAYER
)
8752 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8754 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8758 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8760 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8762 for(uint32 i
= 0; i
< 10; ++i
)
8764 if(((1 << i
) & mask
)==0)
8767 // find invisibility level
8768 uint32 invLevel
= 0;
8769 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8770 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8771 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8772 invLevel
= (*itr
)->GetModifier()->m_amount
;
8774 // find invisibility detect level
8775 uint32 detectLevel
= 0;
8776 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8777 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8778 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8779 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8781 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8783 detectLevel
= ((Player
*)this)->GetDrunkValue();
8786 if(invLevel
<= detectLevel
)
8794 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8796 int32 main_speed_mod
= 0;
8797 float stack_bonus
= 1.0f
;
8798 float non_stack_bonus
= 1.0f
;
8806 if (IsMounted()) // Use on mount auras
8808 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8809 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8810 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8814 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8815 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8816 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8824 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8827 case MOVE_SWIM_BACK
:
8831 if (IsMounted()) // Use on mount auras
8832 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8833 else // Use not mount (shapeshift for example) auras (should stack)
8834 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8835 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8836 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8839 case MOVE_FLIGHT_BACK
:
8842 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8846 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8847 // now we ready for speed calculation
8848 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8856 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8857 // TODO: possible affect only on MOVE_RUN
8858 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8860 // Use speed from aura
8861 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8862 if (speed
> max_speed
)
8871 // Apply strongest slow aura mod to speed
8872 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8874 speed
*=(100.0f
+ slow
)/100.0f
;
8875 SetSpeed(mtype
, speed
, forced
);
8878 float Unit::GetSpeed( UnitMoveType mtype
) const
8880 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8883 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8888 // Update speed only on change
8889 if (m_speed_rate
[mtype
] == rate
)
8892 m_speed_rate
[mtype
] = rate
;
8894 propagateSpeedChange();
8896 // Send speed change packet only for player
8897 if (GetTypeId()!=TYPEID_PLAYER
)
8906 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8909 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8912 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8915 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8917 case MOVE_SWIM_BACK
:
8918 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8920 case MOVE_TURN_RATE
:
8921 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8924 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8926 case MOVE_FLIGHT_BACK
:
8927 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8930 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8934 data
.append(GetPackGUID());
8935 data
<< uint32(0); //movement flags
8936 data
<< uint8(0); //unk
8937 data
<< uint32(getMSTime());
8938 data
<< float(GetPositionX());
8939 data
<< float(GetPositionY());
8940 data
<< float(GetPositionZ());
8941 data
<< float(GetOrientation());
8942 data
<< uint32(0); //flag unk
8943 data
<< float(GetSpeed(mtype
));
8944 SendMessageToSet( &data
, true );
8948 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8949 // and do it only for real sent packets and use run for run/mounted as client expected
8950 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8954 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8957 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8960 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8963 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8965 case MOVE_SWIM_BACK
:
8966 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8968 case MOVE_TURN_RATE
:
8969 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8972 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8974 case MOVE_FLIGHT_BACK
:
8975 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8978 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8981 data
.append(GetPackGUID());
8982 data
<< (uint32
)0; // moveEvent, NUM_PMOVE_EVTS = 0x39
8983 if (mtype
== MOVE_RUN
)
8984 data
<< uint8(0); // new 2.1.0
8985 data
<< float(GetSpeed(mtype
));
8986 SendMessageToSet( &data
, true );
8988 if(Pet
* pet
= GetPet())
8989 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
8992 void Unit::SetHover(bool on
)
8995 CastSpell(this,11010,true);
8997 RemoveAurasDueToSpell(11010);
9000 void Unit::setDeathState(DeathState s
)
9002 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9006 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9008 if(IsNonMeleeSpellCasted(false))
9009 InterruptNonMeleeSpells(false);
9014 RemoveAllAurasOnDeath();
9015 UnsummonAllTotems();
9017 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9018 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9019 // remove aurastates allowing special moves
9020 ClearAllReactives();
9021 ClearDiminishings();
9023 else if(s
== JUST_ALIVED
)
9025 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9028 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9030 //_ApplyAllAuraMods();
9035 /*########################################
9037 ######## AGGRO SYSTEM ########
9039 ########################################*/
9040 bool Unit::CanHaveThreatList() const
9042 // only creatures can have threat list
9043 if( GetTypeId() != TYPEID_UNIT
)
9046 // only alive units can have threat list
9050 // totems can not have threat list
9051 if( ((Creature
*)this)->isTotem() )
9054 // pets can not have a threat list, unless they are controlled by a creature
9055 if( ((Creature
*)this)->isPet() && IS_PLAYER_GUID(((Pet
*)this)->GetOwnerGUID()) )
9061 //======================================================================
9063 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9065 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9068 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9070 return threat
* m_threatModifier
[school
];
9073 //======================================================================
9075 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9077 // Only mobs can manage threat lists
9078 if(CanHaveThreatList())
9079 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9082 //======================================================================
9084 void Unit::DeleteThreatList()
9086 m_ThreatManager
.clearReferences();
9089 //======================================================================
9091 void Unit::TauntApply(Unit
* taunter
)
9093 assert(GetTypeId()== TYPEID_UNIT
);
9095 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9098 if(!CanHaveThreatList())
9101 Unit
*target
= getVictim();
9102 if(target
&& target
== taunter
)
9105 SetInFront(taunter
);
9106 if (((Creature
*)this)->AI())
9107 ((Creature
*)this)->AI()->AttackStart(taunter
);
9109 m_ThreatManager
.tauntApply(taunter
);
9112 //======================================================================
9114 void Unit::TauntFadeOut(Unit
*taunter
)
9116 assert(GetTypeId()== TYPEID_UNIT
);
9118 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9121 if(!CanHaveThreatList())
9124 Unit
*target
= getVictim();
9125 if(!target
|| target
!= taunter
)
9128 if(m_ThreatManager
.isThreatListEmpty())
9130 if(((Creature
*)this)->AI())
9131 ((Creature
*)this)->AI()->EnterEvadeMode();
9135 m_ThreatManager
.tauntFadeOut(taunter
);
9136 target
= m_ThreatManager
.getHostilTarget();
9138 if (target
&& target
!= taunter
)
9141 if (((Creature
*)this)->AI())
9142 ((Creature
*)this)->AI()->AttackStart(target
);
9146 //======================================================================
9148 bool Unit::SelectHostilTarget()
9150 //function provides main threat functionality
9151 //next-victim-selection algorithm and evade mode are called
9152 //threat list sorting etc.
9154 assert(GetTypeId()== TYPEID_UNIT
);
9155 Unit
* target
= NULL
;
9157 //This function only useful once AI has been initialized
9158 if (!((Creature
*)this)->AI())
9161 if(!m_ThreatManager
.isThreatListEmpty())
9163 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9165 target
= m_ThreatManager
.getHostilTarget();
9171 if(!hasUnitState(UNIT_STAT_STUNNED
))
9173 ((Creature
*)this)->AI()->AttackStart(target
);
9177 // no target but something prevent go to evade mode
9178 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9181 // last case when creature don't must go to evade mode:
9182 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9183 // for example at owner command to pet attack some far away creature
9184 // Note: creature not have targeted movement generator but have attacker in this case
9185 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9187 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9189 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9194 // enter in evade mode in other case
9195 ((Creature
*)this)->AI()->EnterEvadeMode();
9200 //======================================================================
9201 //======================================================================
9202 //======================================================================
9204 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9206 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9208 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9210 int32 level
= int32(getLevel());
9211 if (level
> (int32
)spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9212 level
= (int32
)spellProto
->maxLevel
;
9213 else if (level
< (int32
)spellProto
->baseLevel
)
9214 level
= (int32
)spellProto
->baseLevel
;
9215 level
-= (int32
)spellProto
->spellLevel
;
9217 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9218 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9219 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9220 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9221 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9223 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9224 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9225 int32 value
= basePoints
+ randvalue
;
9227 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9228 value
+= (int32
)(comboDamage
* comboPoints
);
9230 if(Player
* modOwner
= GetSpellModOwner())
9232 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9233 switch(effect_index
)
9236 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9239 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9242 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9247 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9248 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9249 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9250 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9255 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9257 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9259 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9261 int32 minduration
= GetSpellDuration(spellProto
);
9262 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9266 if( minduration
!= -1 && minduration
!= maxduration
)
9267 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9269 duration
= minduration
;
9273 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9274 // Find total mod value (negative bonus)
9275 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9276 // Find max mod (negative bonus)
9277 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9279 int32 durationMod
= 0;
9280 // Select strongest negative mod
9281 if (durationMod_always
> durationMod_not_stack
)
9282 durationMod
= durationMod_not_stack
;
9284 durationMod
= durationMod_always
;
9286 if (durationMod
!= 0)
9287 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9289 if (duration
< 0) duration
= 0;
9295 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9297 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9299 if(i
->DRGroup
!= group
)
9303 return DIMINISHING_LEVEL_1
;
9306 return DIMINISHING_LEVEL_1
;
9308 // If last spell was casted more than 15 seconds ago - reset the count.
9309 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9311 i
->hitCount
= DIMINISHING_LEVEL_1
;
9312 return DIMINISHING_LEVEL_1
;
9314 // or else increase the count.
9317 return DiminishingLevels(i
->hitCount
);
9320 return DIMINISHING_LEVEL_1
;
9323 void Unit::IncrDiminishing(DiminishingGroup group
)
9325 // Checking for existing in the table
9326 bool IsExist
= false;
9327 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9329 if(i
->DRGroup
!= group
)
9333 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9340 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9343 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9345 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9348 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9349 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9351 // test pet/charm masters instead pets/charmeds
9352 Unit
const* targetOwner
= GetCharmerOrOwner();
9353 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9355 Unit
const* target
= targetOwner
? targetOwner
: this;
9356 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9358 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9364 // Some diminishings applies to mobs too (for example, Stun)
9365 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9367 DiminishingLevels diminish
= Level
;
9370 case DIMINISHING_LEVEL_1
: break;
9371 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9372 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9373 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9378 duration
= int32(duration
* mod
);
9381 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9383 // Checking for existing in the table
9384 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9386 if(i
->DRGroup
!= group
)
9389 i
->hitTime
= getMSTime();
9400 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9402 return ObjectAccessor::GetUnit(object
,guid
);
9405 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9407 return isVisibleForOrDetect(u
, false, inVisibleList
, false);
9410 uint32
Unit::GetCreatureType() const
9412 if(GetTypeId() == TYPEID_PLAYER
)
9414 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9415 if(ssEntry
&& ssEntry
->creatureType
> 0)
9416 return ssEntry
->creatureType
;
9418 return CREATURE_TYPE_HUMANOID
;
9421 return ((Creature
*)this)->GetCreatureInfo()->type
;
9424 /*#######################################
9426 ######## STAT SYSTEM ########
9428 #######################################*/
9430 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9432 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9434 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9440 switch(modifierType
)
9444 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9448 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9451 val
= (100.0f
+ amount
) / 100.0f
;
9452 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9459 if(!CanModifyStats())
9464 case UNIT_MOD_STAT_STRENGTH
:
9465 case UNIT_MOD_STAT_AGILITY
:
9466 case UNIT_MOD_STAT_STAMINA
:
9467 case UNIT_MOD_STAT_INTELLECT
:
9468 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9470 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9471 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9475 case UNIT_MOD_FOCUS
:
9476 case UNIT_MOD_ENERGY
:
9477 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9479 case UNIT_MOD_RESISTANCE_HOLY
:
9480 case UNIT_MOD_RESISTANCE_FIRE
:
9481 case UNIT_MOD_RESISTANCE_NATURE
:
9482 case UNIT_MOD_RESISTANCE_FROST
:
9483 case UNIT_MOD_RESISTANCE_SHADOW
:
9484 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9486 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9487 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9489 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9490 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9491 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9500 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9502 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9504 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9508 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9511 return m_auraModifiersGroup
[unitMod
][modifierType
];
9514 float Unit::GetTotalStatValue(Stats stat
) const
9516 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9518 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9521 // value = ((base_value * base_pct) + total_value) * total_pct
9522 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9523 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9524 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9525 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9530 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9532 if(unitMod
>= UNIT_MOD_END
)
9534 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9538 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9541 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9542 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9543 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9544 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9549 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9551 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9555 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9556 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9557 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9558 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9559 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9560 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9569 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9571 Stats stat
= STAT_STRENGTH
;
9575 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9576 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9577 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9578 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9579 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9588 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9590 Powers power
= POWER_MANA
;
9594 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9595 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9596 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9597 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9598 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9607 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9609 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9611 float val
= GetTotalAuraModValue(unitMod
);
9618 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9620 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9623 return m_weaponDamage
[attType
][type
];
9626 void Unit::SetLevel(uint32 lvl
)
9628 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9631 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9632 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9635 void Unit::SetHealth(uint32 val
)
9637 uint32 maxHealth
= GetMaxHealth();
9641 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9644 if(GetTypeId() == TYPEID_PLAYER
)
9646 if(((Player
*)this)->GetGroup())
9647 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9649 else if(((Creature
*)this)->isPet())
9651 Pet
*pet
= ((Pet
*)this);
9652 if(pet
->isControlled())
9654 Unit
*owner
= GetOwner();
9655 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9656 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9661 void Unit::SetMaxHealth(uint32 val
)
9663 uint32 health
= GetHealth();
9664 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9667 if(GetTypeId() == TYPEID_PLAYER
)
9669 if(((Player
*)this)->GetGroup())
9670 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9672 else if(((Creature
*)this)->isPet())
9674 Pet
*pet
= ((Pet
*)this);
9675 if(pet
->isControlled())
9677 Unit
*owner
= GetOwner();
9678 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9679 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9687 void Unit::SetPower(Powers power
, uint32 val
)
9689 if(GetPower(power
) == val
)
9692 uint32 maxPower
= GetMaxPower(power
);
9696 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9699 if(GetTypeId() == TYPEID_PLAYER
)
9701 if(((Player
*)this)->GetGroup())
9702 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9704 else if(((Creature
*)this)->isPet())
9706 Pet
*pet
= ((Pet
*)this);
9707 if(pet
->isControlled())
9709 Unit
*owner
= GetOwner();
9710 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9711 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9714 // Update the pet's character sheet with happiness damage bonus
9715 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9717 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9722 void Unit::SetMaxPower(Powers power
, uint32 val
)
9724 uint32 cur_power
= GetPower(power
);
9725 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9728 if(GetTypeId() == TYPEID_PLAYER
)
9730 if(((Player
*)this)->GetGroup())
9731 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9733 else if(((Creature
*)this)->isPet())
9735 Pet
*pet
= ((Pet
*)this);
9736 if(pet
->isControlled())
9738 Unit
*owner
= GetOwner();
9739 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9740 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9745 SetPower(power
, val
);
9748 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9750 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9753 if(GetTypeId() == TYPEID_PLAYER
)
9755 if(((Player
*)this)->GetGroup())
9756 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9758 else if(((Creature
*)this)->isPet())
9760 Pet
*pet
= ((Pet
*)this);
9761 if(pet
->isControlled())
9763 Unit
*owner
= GetOwner();
9764 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9765 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9770 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9772 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9775 if(GetTypeId() == TYPEID_PLAYER
)
9777 if(((Player
*)this)->GetGroup())
9778 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9780 else if(((Creature
*)this)->isPet())
9782 Pet
*pet
= ((Pet
*)this);
9783 if(pet
->isControlled())
9785 Unit
*owner
= GetOwner();
9786 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9787 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9792 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9794 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9796 tAuraProcTriggerDamage
.push_back(aura
);
9798 tAuraProcTriggerDamage
.remove(aura
);
9801 uint32
Unit::GetCreatePowers( Powers power
) const
9803 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9806 case POWER_MANA
: return GetCreateMana();
9807 case POWER_RAGE
: return 1000;
9808 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9809 case POWER_ENERGY
: return 100;
9810 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9816 void Unit::AddToWorld()
9818 Object::AddToWorld();
9821 void Unit::RemoveFromWorld()
9826 RemoveNotOwnSingleTargetAuras();
9829 Object::RemoveFromWorld();
9832 void Unit::CleanupsBeforeDelete()
9834 if(m_uint32Values
) // only for fully created object
9836 InterruptNonMeleeSpells(true);
9837 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9839 ClearComboPointHolders();
9841 getHostilRefManager().setOnlineOfflineState(false);
9843 RemoveAllGameObjects();
9844 RemoveAllDynObjects();
9845 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9850 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9853 m_charmInfo
= new CharmInfo(charm
);
9857 CharmInfo::CharmInfo(Unit
* unit
)
9858 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9860 for(int i
=0; i
<4; ++i
)
9862 m_charmspells
[i
].spellId
= 0;
9863 m_charmspells
[i
].active
= ACT_DISABLED
;
9867 void CharmInfo::InitPetActionBar()
9869 // the first 3 SpellOrActions are attack, follow and stay
9870 for(uint32 i
= 0; i
< 3; i
++)
9872 PetActionBar
[i
].Type
= ACT_COMMAND
;
9873 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9875 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9876 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9878 for(uint32 i
=0; i
< 4; i
++)
9880 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9881 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9885 void CharmInfo::InitEmptyActionBar()
9887 for(uint32 x
= 1; x
< 10; ++x
)
9889 PetActionBar
[x
].Type
= ACT_CAST
;
9890 PetActionBar
[x
].SpellOrAction
= 0;
9892 PetActionBar
[0].Type
= ACT_COMMAND
;
9893 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9896 void CharmInfo::InitPossessCreateSpells()
9898 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9901 InitEmptyActionBar(); //charm action bar
9903 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9905 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9906 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9908 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9912 void CharmInfo::InitCharmCreateSpells()
9914 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9916 InitEmptyActionBar();
9922 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9924 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9925 m_charmspells
[x
].spellId
= spellId
;
9930 if (IsPassiveSpell(spellId
))
9932 m_unit
->CastSpell(m_unit
, spellId
, true);
9933 m_charmspells
[x
].active
= ACT_PASSIVE
;
9937 ActiveStates newstate
;
9938 bool onlyselfcast
= true;
9939 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9941 if(!spellInfo
) onlyselfcast
= false;
9942 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9944 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9945 onlyselfcast
= false;
9948 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9949 newstate
= ACT_DISABLED
;
9951 newstate
= ACT_CAST
;
9953 AddSpellToAB(0, spellId
, newstate
);
9958 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9960 for(uint8 i
= 0; i
< 10; i
++)
9962 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9964 PetActionBar
[i
].SpellOrAction
= newid
;
9967 if(newstate
== ACT_DECIDE
)
9968 PetActionBar
[i
].Type
= ACT_DISABLED
;
9970 PetActionBar
[i
].Type
= newstate
;
9979 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9981 if(IsPassiveSpell(spellid
))
9984 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9986 if(spellid
== m_charmspells
[x
].spellId
)
9988 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
9993 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
9995 m_petnumber
= petnumber
;
9997 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
9999 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10002 bool Unit::isFrozen() const
10004 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10005 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10006 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10011 struct ProcTriggeredData
10013 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
10014 : triggeredByAura(_triggeredByAura
),
10015 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10016 cooldown(_cooldown
)
10019 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10020 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10021 uint32 cooldown
; // possible hidden cooldown
10024 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10026 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10028 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10030 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10031 ProcTriggeredList procTriggered
;
10033 AuraList
const& auras
= GetAurasByType(*aur
);
10034 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10040 uint32 cooldown
; // returned at next line
10041 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10044 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10047 // Handle effects proceed this time
10048 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10050 // Some auras can be deleted in function called in this loop (except first, ofc)
10051 // Until storing auras in std::multimap to hard check deleting by another way
10052 if(i
!= procTriggered
.begin())
10054 bool found
= false;
10055 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10056 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10057 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10059 if(itr
->second
==i
->triggeredByAura
)
10068 sLog
.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur
,i
->triggeredByAura_SpellPair
.first
,i
->triggeredByAura_SpellPair
.second
);
10069 sLog
.outError("It can be deleted one from early processed auras:");
10070 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10071 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10072 sLog
.outError(" <end of list>");
10077 /// this is aura triggering code call
10078 Aura
* triggeredByAura
= i
->triggeredByAura
;
10080 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10081 /// used in speedup code check before check aura existance.
10082 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10084 /// success in event proccesing
10085 /// used in speedup code check before check aura existance.
10086 bool casted
= false;
10088 /// process triggered code
10091 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10093 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10094 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10095 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10098 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10100 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10101 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10102 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10103 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10107 case SPELL_AURA_DUMMY
:
10109 uint32 effect
= triggeredByAura
->GetEffIndex();
10110 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10111 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10112 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10115 case SPELL_AURA_PRAYER_OF_MENDING
:
10117 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10118 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10120 casted
= HandleMeandingAuraProc(triggeredByAura
);
10123 case SPELL_AURA_MOD_HASTE
:
10125 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10126 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10127 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10130 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10132 // nothing do, just charges counter
10133 // but count only in case appropriate school damage
10134 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10137 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10139 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10140 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10141 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10146 // nothing do, just charges counter
10152 /// Update charge (aura can be removed by triggers)
10153 if(casted
&& triggeredByAuraWithCharges
)
10155 /// need re-found aura (can be dropped by triggers)
10156 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10157 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10158 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10160 if(itr
->second
== triggeredByAura
) // pointer still valid
10162 if(triggeredByAura
->m_procCharges
> 0)
10163 triggeredByAura
->m_procCharges
-= 1;
10165 triggeredByAura
->UpdateAuraCharges();
10172 /// Safely remove auras with zero charges
10173 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10176 if((*i
)->m_procCharges
== 0)
10178 RemoveAurasDueToSpell((*i
)->GetId());
10179 next
= auras
.begin();
10185 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10187 return SPELL_SCHOOL_MASK_NORMAL
;
10190 Player
* Unit::GetSpellModOwner()
10192 if(GetTypeId()==TYPEID_PLAYER
)
10193 return (Player
*)this;
10194 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10196 Unit
* owner
= GetOwner();
10197 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10198 return (Player
*)owner
;
10203 ///----------Pet responses methods-----------------
10204 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10206 Unit
*owner
= GetCharmerOrOwner();
10207 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10210 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10211 data
<< uint32(spellid
);
10212 data
<< uint8(msg
);
10213 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10216 void Unit::SendPetActionFeedback (uint8 msg
)
10218 Unit
* owner
= GetOwner();
10219 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10222 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10223 data
<< uint8(msg
);
10224 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10227 void Unit::SendPetTalk (uint32 pettalk
)
10229 Unit
* owner
= GetOwner();
10230 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10233 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10234 data
<< uint64(GetGUID());
10235 data
<< uint32(pettalk
);
10236 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10239 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10241 Unit
* owner
= GetOwner();
10242 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10245 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10246 data
<< uint64(GetGUID());
10247 data
<< uint8(0x0); // flags (0x1, 0x2)
10248 data
<< uint32(spellid
);
10249 data
<< uint32(cooltime
);
10251 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10254 void Unit::SendPetClearCooldown (uint32 spellid
)
10256 Unit
* owner
= GetOwner();
10257 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10260 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10261 data
<< uint32(spellid
);
10262 data
<< uint64(GetGUID());
10263 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10266 void Unit::SendPetAIReaction(uint64 guid
)
10268 Unit
* owner
= GetOwner();
10269 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10272 WorldPacket
data(SMSG_AI_REACTION
, 12);
10273 data
<< uint64(guid
) << uint32(00000002);
10274 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10277 ///----------End of Pet responses methods----------
10279 void Unit::StopMoving()
10281 clearUnitState(UNIT_STAT_MOVING
);
10283 // send explicit stop packet
10284 // rely on vmaps here because for example stormwind is in air
10285 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10286 //if (fabs(GetPositionZ() - z) < 2.0f)
10287 // Relocate(GetPositionX(), GetPositionY(), z);
10288 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10290 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10292 // update position and orientation;
10294 BuildHeartBeatMsg(&data
);
10295 SendMessageToSet(&data
,false);
10298 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10302 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10305 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10307 GetMotionMaster()->MovementExpired(false);
10308 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10310 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10312 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10316 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10318 GetMotionMaster()->MovementExpired(false);
10320 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10322 // restore appropriate movement generator
10324 GetMotionMaster()->MoveChase(getVictim());
10326 GetMotionMaster()->Initialize();
10328 // attack caster if can
10329 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10330 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10331 ((Creature
*)this)->AI()->AttackStart(caster
);
10335 if (GetTypeId() == TYPEID_PLAYER
)
10336 ((Player
*)this)->SetClientControl(this, !apply
);
10339 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10343 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10345 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10347 GetMotionMaster()->MoveConfused();
10351 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10353 GetMotionMaster()->MovementExpired(false);
10355 if (GetTypeId() == TYPEID_UNIT
)
10357 // if in combat restore movement generator
10359 GetMotionMaster()->MoveChase(getVictim());
10363 if(GetTypeId() == TYPEID_PLAYER
)
10364 ((Player
*)this)->SetClientControl(this, !apply
);
10367 bool Unit::IsSitState() const
10369 uint8 s
= getStandState();
10370 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10371 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10372 s
== PLAYER_STATE_SIT
;
10375 bool Unit::IsStandState() const
10377 uint8 s
= getStandState();
10378 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10381 void Unit::SetStandState(uint8 state
)
10383 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10385 if (IsStandState())
10386 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10388 if(GetTypeId()==TYPEID_PLAYER
)
10390 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10391 data
<< (uint8
)state
;
10392 ((Player
*)this)->GetSession()->SendPacket(&data
);
10396 bool Unit::IsPolymorphed() const
10398 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10401 void Unit::SetDisplayId(uint32 modelId
)
10403 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10405 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10407 Pet
*pet
= ((Pet
*)this);
10408 if(!pet
->isControlled())
10410 Unit
*owner
= GetOwner();
10411 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10412 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10416 void Unit::ClearComboPointHolders()
10418 while(!m_ComboPointHolders
.empty())
10420 uint32 lowguid
= *m_ComboPointHolders
.begin();
10422 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10423 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10424 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10426 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10430 void Unit::ClearAllReactives()
10433 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10434 m_reactiveTimer
[i
] = 0;
10436 if (HasAuraState( AURA_STATE_DEFENSE
))
10437 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10438 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10439 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10440 if (HasAuraState( AURA_STATE_CRIT
))
10441 ModifyAuraState(AURA_STATE_CRIT
, false);
10442 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10443 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10445 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10446 ((Player
*)this)->ClearComboPoints();
10449 void Unit::UpdateReactives( uint32 p_time
)
10451 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10453 ReactiveType reactive
= ReactiveType(i
);
10455 if(!m_reactiveTimer
[reactive
])
10458 if ( m_reactiveTimer
[reactive
] <= p_time
)
10460 m_reactiveTimer
[reactive
] = 0;
10462 switch ( reactive
)
10464 case REACTIVE_DEFENSE
:
10465 if (HasAuraState(AURA_STATE_DEFENSE
))
10466 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10468 case REACTIVE_HUNTER_PARRY
:
10469 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10470 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10472 case REACTIVE_CRIT
:
10473 if (HasAuraState(AURA_STATE_CRIT
))
10474 ModifyAuraState(AURA_STATE_CRIT
, false);
10476 case REACTIVE_HUNTER_CRIT
:
10477 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10478 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10480 case REACTIVE_OVERPOWER
:
10481 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10482 ((Player
*)this)->ClearComboPoints();
10490 m_reactiveTimer
[reactive
] -= p_time
;
10495 Unit
* Unit::SelectNearbyTarget() const
10497 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10499 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10500 cell
.SetNoCreate();
10502 std::list
<Unit
*> targets
;
10505 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10506 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10508 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10509 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10511 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10512 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *GetMap());
10513 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *GetMap());
10516 // remove current target
10518 targets
.remove(getVictim());
10520 // remove not LoS targets
10521 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10523 if(!IsWithinLOSInMap(*tIter
))
10525 std::list
<Unit
*>::iterator tIter2
= tIter
;
10527 targets
.erase(tIter2
);
10533 // no appropriate targets
10534 if(targets
.empty())
10538 uint32 rIdx
= urand(0,targets
.size()-1);
10539 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10540 for(uint32 i
= 0; i
< rIdx
; ++i
)
10546 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10550 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10551 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10555 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10556 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10560 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10563 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10565 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10568 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10570 // Not apply this to creature casted spells with casttime==0
10571 if(CastingTime
==0 && GetTypeId()==TYPEID_UNIT
&& !((Creature
*)this)->isPet())
10574 if (CastingTime
> 7000) CastingTime
= 7000;
10575 if (CastingTime
< 1500) CastingTime
= 1500;
10577 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10578 CastingTime
= 3500;
10580 int32 overTime
= 0;
10582 bool DirectDamage
= false;
10583 bool AreaEffect
= false;
10585 for ( uint32 i
=0; i
<3;i
++)
10587 switch ( spellProto
->Effect
[i
] )
10589 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10590 case SPELL_EFFECT_POWER_DRAIN
:
10591 case SPELL_EFFECT_HEALTH_LEECH
:
10592 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10593 case SPELL_EFFECT_POWER_BURN
:
10594 case SPELL_EFFECT_HEAL
:
10595 DirectDamage
= true;
10597 case SPELL_EFFECT_APPLY_AURA
:
10598 switch ( spellProto
->EffectApplyAuraName
[i
] )
10600 case SPELL_AURA_PERIODIC_DAMAGE
:
10601 case SPELL_AURA_PERIODIC_HEAL
:
10602 case SPELL_AURA_PERIODIC_LEECH
:
10603 if ( GetSpellDuration(spellProto
) )
10604 overTime
= GetSpellDuration(spellProto
);
10607 // -5% per additional effect
10615 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10619 // Combined Spells with Both Over Time and Direct Damage
10620 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10622 // mainly for DoTs which are 3500 here otherwise
10623 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10624 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10625 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10626 // Portion to Over Time
10627 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10629 if ( damagetype
== DOT
)
10630 CastingTime
= uint32(CastingTime
* PtOT
);
10631 else if ( PtOT
< 1.0f
)
10632 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10637 // Area Effect Spells receive only half of bonus
10641 // -5% of total per any additional effect
10642 for ( uint8 i
=0; i
<effects
; ++i
)
10644 if ( CastingTime
> 175 )
10646 CastingTime
-= 175;
10655 return CastingTime
;
10658 void Unit::UpdateAuraForGroup(uint8 slot
)
10660 if(GetTypeId() == TYPEID_PLAYER
)
10662 Player
* player
= (Player
*)this;
10663 if(player
->GetGroup())
10665 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10666 player
->SetAuraUpdateMask(slot
);
10669 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10671 Pet
*pet
= ((Pet
*)this);
10672 if(pet
->isControlled())
10674 Unit
*owner
= GetOwner();
10675 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10677 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10678 pet
->SetAuraUpdateMask(slot
);
10684 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10686 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10687 return float(GetAttackTime(attType
))/1000.0f
;
10689 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10691 return 2.4; // fist attack
10693 switch (Weapon
->GetProto()->InventoryType
)
10695 case INVTYPE_2HWEAPON
:
10697 case INVTYPE_RANGED
:
10698 case INVTYPE_RANGEDRIGHT
:
10699 case INVTYPE_THROWN
:
10701 case INVTYPE_WEAPON
:
10702 case INVTYPE_WEAPONMAINHAND
:
10703 case INVTYPE_WEAPONOFFHAND
:
10705 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10709 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10711 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10712 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10713 if ((*itr
)->GetId() == spell_id
)
10719 bool Unit::IsUnderLastManaUseEffect() const
10721 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10724 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10726 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10728 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10731 player
->SetContestedPvPTimer(30000);
10732 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10734 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10735 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10736 // call MoveInLineOfSight for nearby contested guards
10737 SetVisibility(GetVisibility());
10739 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10741 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10742 // call MoveInLineOfSight for nearby contested guards
10743 SetVisibility(GetVisibility());
10747 void Unit::AddPetAura(PetAura
const* petSpell
)
10749 m_petAuras
.insert(petSpell
);
10750 if(Pet
* pet
= GetPet())
10751 pet
->CastPetAura(petSpell
);
10754 void Unit::RemovePetAura(PetAura
const* petSpell
)
10756 m_petAuras
.erase(petSpell
);
10757 if(Pet
* pet
= GetPet())
10758 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10761 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10763 Pet
* pet
= new Pet(HUNTER_PET
);
10765 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10771 pet
->SetOwnerGUID(GetGUID());
10772 pet
->SetCreatorGUID(GetGUID());
10773 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, getFaction());
10774 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10776 if(!pet
->InitStatsForLevel(creatureTarget
->getLevel()))
10778 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10783 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10784 // this enables pet details window (Shift+P)
10785 pet
->AIM_Initialize();
10786 pet
->InitPetCreateSpells();
10787 pet
->SetHealth(pet
->GetMaxHealth());
10792 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10794 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10796 if(!spellProcEvent
)
10798 // used to prevent spam in log about same non-handled spells
10799 static std::set
<uint32
> nonHandledSpellProcSet
;
10801 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10803 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10804 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10807 // spell.dbc use totally different flags, that only can create problems if used.
10811 // Check spellProcEvent data requirements
10812 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10815 // Check if current equipment allows aura to proc
10816 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10818 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10820 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10822 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10825 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10827 // Check if player is wearing shield
10828 Item
*item
= ((Player
*)this)->GetShield(true);
10829 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10834 float chance
= (float)spellProto
->procChance
;
10836 if(Player
* modOwner
= GetSpellModOwner())
10837 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10839 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10841 uint32 WeaponSpeed
= GetAttackTime(attType
);
10842 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10845 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10846 return roll_chance_f(chance
);
10849 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10851 // aura can be deleted at casts
10852 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10853 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10854 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10855 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10858 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10860 // current aura expire
10861 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10863 // next target selection
10864 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10867 if (spellProto
->EffectRadiusIndex
[effIdx
])
10868 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10870 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10872 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10874 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10876 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10878 // aura will applied from caster, but spell casted from current aura holder
10879 SpellModifier
*mod
= new SpellModifier
;
10880 mod
->op
= SPELLMOD_CHARGES
;
10881 mod
->value
= jumps
-5; // negative
10882 mod
->type
= SPELLMOD_FLAT
;
10883 mod
->spellId
= spellProto
->Id
;
10884 mod
->effectId
= effIdx
;
10885 mod
->lastAffected
= NULL
;
10886 mod
->mask
= spellProto
->SpellFamilyFlags
;
10889 caster
->AddSpellMod(mod
, true);
10890 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10891 caster
->AddSpellMod(mod
, false);
10897 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10901 void Unit::RemoveAurasAtChanneledTarget(SpellEntry
const* spellInfo
)
10903 uint64 target_guid
= GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
);
10905 if(!IS_UNIT_GUID(target_guid
))
10908 Unit
* target
= ObjectAccessor::GetUnit(*this, target_guid
);
10912 for (AuraMap::iterator iter
= target
->GetAuras().begin(); iter
!= target
->GetAuras().end(); )
10914 if (iter
->second
->GetId() == spellInfo
->Id
&& iter
->second
->GetCasterGUID()==GetGUID())
10915 target
->RemoveAura(iter
);