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_WALKBACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIMBACK
56 3.141594f
, // MOVE_TURN
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_AURAS
; ++i
)
187 m_visibleAuras
[i
] = 0;
188 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
189 m_spellImmune
[i
].clear();
190 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
192 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
193 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
194 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
195 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
197 // implement 50% base damage from offhand
198 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
200 for (int i
= 0; i
< 3; i
++)
202 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
203 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
205 for (int i
= 0; i
< MAX_STATS
; i
++)
206 m_createStats
[i
] = 0.0f
;
209 m_modMeleeHitChance
= 0.0f
;
210 m_modRangedHitChance
= 0.0f
;
211 m_modSpellHitChance
= 0.0f
;
212 m_baseSpellCritChance
= 5;
217 //m_victimThreat = 0.0f;
218 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
219 m_threatModifier
[i
] = 1.0f
;
221 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
222 m_speed_rate
[i
] = 1.0f
;
226 m_unit_movement_flags
= 0;
228 // remove aurastates allowing special moves
229 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
230 m_reactiveTimer
[i
] = 0;
235 // set current spells as deletable
236 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
238 // spell may be safely deleted now
239 if (m_currentSpells
[i
]) m_currentSpells
[i
]->SetDeletable(true);
240 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( )
390 data
<< GetOrientation( );
392 data
<< uint32( MovementFlags
);
393 data
<< uint32( traveltime
);
394 data
<< uint32( pathSize
);
395 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
397 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
398 SendMessageToSet(&data
, true);
401 void Unit::resetAttackTimer(WeaponAttackType type
)
403 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
406 bool Unit::canReachWithAttack(Unit
*pVictim
) const
409 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
412 return IsWithinDistInMap(pVictim
, reach
);
415 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
417 if (auraType
>= TOTAL_AURAS
) return;
418 AuraList::iterator iter
, next
;
419 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
426 RemoveAurasDueToSpell((*iter
)->GetId());
427 if (!m_modAuras
[auraType
].empty())
428 next
= m_modAuras
[auraType
].begin();
435 bool Unit::HasAuraType(AuraType auraType
) const
437 return (!m_modAuras
[auraType
].empty());
440 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
441 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
443 if(!HasAuraType(auraType
))
446 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
447 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
448 float chance
= float(damage
) / max_dmg
* 100.0f
;
449 if (roll_chance_f(chance
))
450 RemoveSpellsCausingAura(auraType
);
453 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
455 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
458 //You don't lose health from damage taken from another player while in a sanctuary
459 //You still see it in the combat log though
460 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
462 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
463 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
467 // remove affects from victim (including from 0 damage and DoTs)
469 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
471 // remove affects from attacker at any non-DoT damage (including 0 damage)
472 if( damagetype
!= DOT
)
474 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
475 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
478 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
480 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
481 pVictim
->SetStandState(PLAYER_STATE_NONE
);
484 //Script Event damage Deal
485 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
486 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
487 //Script Event damage taken
488 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
489 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
493 // Rage from physical damage received .
494 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
495 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
500 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
501 // root type spells do not dispell the root effect
502 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
503 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
505 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
507 // no xp,health if type 8 /critters/
508 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
510 pVictim
->setDeathState(JUST_DIED
);
511 pVictim
->SetHealth(0);
513 // allow loot only if has loot_id in creature_template
514 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
515 if(cInfo
&& cInfo
->lootid
)
516 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
518 // some critters required for quests
519 if(GetTypeId() == TYPEID_PLAYER
)
520 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
525 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
526 ((Creature
*)pVictim
)->AI()->AttackStart(this);
529 DEBUG_LOG("DealDamageStart");
531 uint32 health
= pVictim
->GetHealth();
532 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
534 // duel ends when player has 1 or less hp
535 bool duel_hasEnded
= false;
536 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
538 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
539 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
542 duel_hasEnded
= true;
545 if(pVictim
!= this && damagetype
!= DOT
)
547 SetInCombatWith(pVictim
);
548 pVictim
->SetInCombatWith(this);
550 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
551 SetContestedPvP(attackedPlayer
);
554 // Rage from Damage made (only from direct weapon damage)
555 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
557 uint32 weaponSpeedHitFactor
;
559 switch(cleanDamage
->attackType
)
563 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
564 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
566 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
568 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
574 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
575 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
577 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
579 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
588 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
590 if(((Player
*)pVictim
)->InBattleGround())
592 Player
*killer
= ((Player
*)this);
593 if(killer
!= ((Player
*)pVictim
))
594 if(BattleGround
*bg
= killer
->GetBattleGround())
595 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
599 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
600 ((Creature
*)pVictim
)->SetLootRecipient(this);
601 if (health
<= damage
)
603 // battleground things
604 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
606 Player
*killed
= ((Player
*)pVictim
);
607 Player
*killer
= NULL
;
608 if(GetTypeId() == TYPEID_PLAYER
)
609 killer
= ((Player
*)this);
610 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
612 Unit
*owner
= GetOwner();
613 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
614 killer
= ((Player
*)owner
);
618 if(BattleGround
*bg
= killed
->GetBattleGround())
619 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
622 DEBUG_LOG("DealDamage: victim just died");
624 // find player: owner of controlled `this` or `this` itself maybe
625 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
627 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
628 player
= ((Creature
*)pVictim
)->GetLootRecipient();
629 // Reward player, his pets, and group/raid members
630 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
631 if(player
&& player
!=pVictim
)
632 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
633 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
635 DEBUG_LOG("DealDamageAttackStop");
638 pVictim
->CombatStop();
639 pVictim
->getHostilRefManager().deleteReferences();
641 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
643 // if talent known but not triggered (check priest class for speedup check)
644 Aura
* spiritOfRedemtionTalentReady
= NULL
;
645 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
646 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
648 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
649 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
651 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
653 spiritOfRedemtionTalentReady
= *itr
;
659 DEBUG_LOG("SET JUST_DIED");
660 if(!spiritOfRedemtionTalentReady
)
661 pVictim
->setDeathState(JUST_DIED
);
663 DEBUG_LOG("DealDamageHealth1");
665 if(spiritOfRedemtionTalentReady
)
667 // save value before aura remove
668 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
670 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
672 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
673 pVictim
->RemoveAllAurasOnDeath();
675 // restore for use at real death
676 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
678 // FORM_SPIRITOFREDEMPTION and related auras
679 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
682 pVictim
->SetHealth(0);
684 // remember victim PvP death for corpse type and corpse reclaim delay
685 // at original death (not at SpiritOfRedemtionTalent timeout)
686 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
687 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
689 // Call KilledUnit for creatures
690 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
691 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
694 if ( pVictim
->GetTypeId() == TYPEID_PLAYER
)
696 if(GetTypeId() == TYPEID_UNIT
)
697 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
, GetEntry());
698 else if(GetTypeId() == TYPEID_PLAYER
)
699 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
, 1);
702 // 10% durability loss on death
703 // clean InHateListOf
704 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
706 // only if not player and not controlled by player pet. And not at BG
707 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
709 DEBUG_LOG("We are dead, loosing 10 percents durability");
710 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
711 // durability lost message
712 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
713 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
716 else // creature died
718 DEBUG_LOG("DealDamageNotPlayer");
719 Creature
*cVictim
= (Creature
*)pVictim
;
721 if(!cVictim
->isPet())
723 cVictim
->DeleteThreatList();
724 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
726 // Call creature just died function
728 cVictim
->AI()->JustDied(this);
730 // Dungeon specific stuff, only applies to players killing creatures
731 if(cVictim
->GetInstanceId())
733 Map
*m
= cVictim
->GetMap();
734 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
735 // TODO: do instance binding anyway if the charmer/owner is offline
737 if(m
->IsDungeon() && creditedPlayer
)
739 if(m
->IsRaid() || m
->IsHeroic())
741 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
742 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
746 // the reset time is set but not added to the scheduler
747 // until the players leave the instance
748 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
749 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
750 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
756 // last damage from non duel opponent or opponent controlled creature
759 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
760 Player
*he
= (Player
*)pVictim
;
764 he
->duel
->opponent
->CombatStopWithPets(true);
765 he
->CombatStopWithPets(true);
767 he
->DuelComplete(DUEL_INTERUPTED
);
770 else // if (health <= damage)
772 DEBUG_LOG("DealDamageAlive");
774 pVictim
->ModifyHealth(- (int32
)damage
);
776 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
777 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
779 uint32 procVictim
= PROC_FLAG_NONE
;
781 // if just dropped below 20% (for CheatDeath)
782 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
783 procVictim
= PROC_FLAG_LOW_HEALTH
;
785 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
788 if(damagetype
!= DOT
)
792 // if have target and damage pVictim just call AI recation
793 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
794 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
798 // if not have main target then attack state with target (including AI call)
799 //start melee attacks only after melee hit
800 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
804 // polymorphed and other negative transformed cases
805 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
806 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
808 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
809 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
811 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
813 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
814 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
816 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
818 else // victim is a player
820 // Rage from damage received
821 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
823 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
824 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
827 // random durability for items (HIT TAKEN)
828 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
830 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
831 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
835 if(GetTypeId()==TYPEID_PLAYER
)
837 // random durability for items (HIT DONE)
838 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
840 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
841 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
845 // TODO: Store auras by interrupt flag to speed this up.
846 AuraMap
& vAuras
= pVictim
->GetAuras();
847 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
849 const SpellEntry
*se
= i
->second
->GetSpellProto();
851 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
854 if (se
->procFlags
& (1<<3))
856 if (!roll_chance_i(se
->procChance
))
861 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
862 // FIXME: this may cause the auras with proc chance to be rerolled several times
863 next
= vAuras
.begin();
868 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
870 if( damagetype
!= DOT
)
872 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
874 // skip channeled spell (processed differently below)
875 if (i
== CURRENT_CHANNELED_SPELL
)
878 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
879 if(spell
->getState() == SPELL_STATE_PREPARING
)
884 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
886 if (spell
->getState() == SPELL_STATE_CASTING
)
888 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
889 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
891 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
892 spell
->DelayedChannel();
894 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
896 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
897 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
900 else if (spell
->getState() == SPELL_STATE_DELAYED
)
901 // break channeled spell in delayed state on damage
903 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
904 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
909 // last damage from duel opponent
912 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
913 Player
*he
= (Player
*)pVictim
;
919 he
->duel
->opponent
->CombatStopWithPets(true);
920 he
->CombatStopWithPets(true);
922 he
->CastSpell(he
, 7267, true); // beg
923 he
->DuelComplete(DUEL_WON
);
927 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
932 void Unit::CastStop(uint32 except_spellid
)
934 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
935 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
936 InterruptSpell(i
,false);
939 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
941 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
945 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
949 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
952 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
956 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
961 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
963 if(!originalCaster
&& triggredByAura
)
964 originalCaster
= triggredByAura
->GetCasterGUID();
966 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
968 SpellCastTargets targets
;
969 targets
.setUnitTarget( Victim
);
970 spell
->m_CastItem
= castItem
;
971 spell
->prepare(&targets
, triggredByAura
);
974 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
976 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
980 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
984 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggredByAura
, originalCaster
);
987 void Unit::CastCustomSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
991 sLog
.outError("CastCustomSpell: unknown spell");
996 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
998 if(!originalCaster
&& triggredByAura
)
999 originalCaster
= triggredByAura
->GetCasterGUID();
1001 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1004 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
1007 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1010 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1012 SpellCastTargets targets
;
1013 targets
.setUnitTarget( Victim
);
1014 spell
->m_CastItem
= castItem
;
1015 spell
->prepare(&targets
, triggredByAura
);
1018 // used for scripting
1019 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
1021 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1025 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()));
1029 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
1032 // used for scripting
1033 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
1037 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1042 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1044 if(!originalCaster
&& triggredByAura
)
1045 originalCaster
= triggredByAura
->GetCasterGUID();
1047 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1049 SpellCastTargets targets
;
1050 targets
.setDestination(x
, y
, z
);
1051 spell
->m_CastItem
= castItem
;
1052 spell
->prepare(&targets
, triggredByAura
);
1055 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1057 // TODO this in only generic way, check for exceptions
1058 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1060 // Per-damage calss calculation
1061 switch (spellInfo
->DmgClass
)
1063 // Melee and Ranged Spells
1064 case SPELL_DAMAGE_CLASS_RANGED
:
1065 case SPELL_DAMAGE_CLASS_MELEE
:
1067 // Calculate physical outcome
1068 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1070 //Used to store the Hit Outcome
1071 cleanDamage
->hitOutCome
= outcome
;
1073 // Return miss/evade first (sends miss message)
1076 case MELEE_HIT_EVADE
:
1078 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1082 case MELEE_HIT_MISS
:
1084 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1087 if(GetTypeId()== TYPEID_PLAYER
)
1088 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1090 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1095 // Hitinfo, Victimstate
1096 uint32 hitInfo
= HITINFO_NORMALSWING
;
1097 VictimState victimState
= VICTIMSTATE_NORMAL
;
1100 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1102 uint32 modDamage
=*damage
;
1104 // apply spellmod to Done damage
1105 if(Player
* modOwner
= GetSpellModOwner())
1106 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1108 //Calculate armor mitigation
1109 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1111 // random durability for main hand weapon (ABSORB)
1112 if(damageAfterArmor
< *damage
)
1113 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1114 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1115 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1117 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1118 *damage
= damageAfterArmor
;
1123 // Calculate damage bonus
1124 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1130 case MELEE_HIT_BLOCK_CRIT
:
1131 case MELEE_HIT_CRIT
:
1133 uint32 bonusDmg
= *damage
;
1135 // Apply crit_damage bonus
1136 if(Player
* modOwner
= GetSpellModOwner())
1137 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1139 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1140 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1141 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1142 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1143 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1145 *damage
+= bonusDmg
;
1147 // Resilience - reduce crit damage
1148 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1150 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1151 cleanDamage
->damage
+= resilienceReduction
;
1152 *damage
-= resilienceReduction
;
1156 hitInfo
|= HITINFO_CRITICALHIT
;
1158 ModifyAuraState(AURA_STATE_CRIT
, true);
1159 StartReactiveTimer( REACTIVE_CRIT
);
1161 if(getClass()==CLASS_HUNTER
)
1163 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1164 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1167 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1169 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1170 if (blocked_amount
>= *damage
)
1172 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1173 victimState
= VICTIMSTATE_BLOCKS
;
1174 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1179 // To Help Calculate Rage
1180 cleanDamage
->damage
+= blocked_amount
;
1181 *damage
= *damage
- blocked_amount
;
1184 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1185 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1187 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1190 ((Player
*)pVictim
)->UpdateDefense();
1192 // random durability for main hand weapon (BLOCK)
1193 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1194 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1199 case MELEE_HIT_PARRY
:
1201 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1203 victimState
= VICTIMSTATE_PARRY
;
1205 // Counter-attack ( explained in Unit::DoAttackDamage() )
1206 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1208 // Get attack timers
1209 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1210 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1212 // Reduce attack time
1213 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1215 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1216 float percent60
= 3 * percent20
;
1217 if(offtime
> percent20
&& offtime
<= percent60
)
1219 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1221 else if(offtime
> percent60
)
1223 offtime
-= 2 * percent20
;
1224 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1229 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1230 float percent60
= 3 * percent20
;
1231 if(basetime
> percent20
&& basetime
<= percent60
)
1233 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1235 else if(basetime
> percent60
)
1237 basetime
-= 2 * percent20
;
1238 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1243 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1245 // Update victim defense ?
1246 ((Player
*)pVictim
)->UpdateDefense();
1248 // random durability for main hand weapon (PARRY)
1249 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1250 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1254 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1256 // Mongoose bite - set only Counterattack here
1257 if (pVictim
->getClass() == CLASS_HUNTER
)
1259 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1260 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1264 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1265 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1269 case MELEE_HIT_DODGE
:
1271 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1272 ((Player
*)pVictim
)->UpdateDefense();
1274 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1276 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1277 victimState
= VICTIMSTATE_DODGE
;
1280 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1283 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1285 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1286 StartReactiveTimer( REACTIVE_OVERPOWER
);
1290 if (pVictim
->getClass() != CLASS_ROGUE
)
1292 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1293 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1297 case MELEE_HIT_BLOCK
:
1299 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1300 if (blocked_amount
>= *damage
)
1302 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1303 victimState
= VICTIMSTATE_BLOCKS
;
1304 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1309 // To Help Calculate Rage
1310 cleanDamage
->damage
+= blocked_amount
;
1311 *damage
= *damage
- blocked_amount
;
1314 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1315 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1317 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1320 ((Player
*)pVictim
)->UpdateDefense();
1322 // random durability for main hand weapon (BLOCK)
1323 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1324 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1328 case MELEE_HIT_EVADE
: // already processed early
1329 case MELEE_HIT_MISS
: // already processed early
1330 case MELEE_HIT_GLANCING
:
1331 case MELEE_HIT_CRUSHING
:
1332 case MELEE_HIT_NORMAL
:
1336 // do all damage=0 cases here
1338 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1343 case SPELL_DAMAGE_CLASS_NONE
:
1344 case SPELL_DAMAGE_CLASS_MAGIC
:
1346 // Calculate damage bonus
1347 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1349 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1352 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1354 // Resilience - reduce crit damage
1355 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1357 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1358 if(*damage
> damage_reduction
)
1359 *damage
-= damage_reduction
;
1364 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1366 // spell proc all magic damage==0 case in this function
1370 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1371 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1373 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1380 // TODO this in only generic way, check for exceptions
1381 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1384 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1386 if(!this || !pVictim
)
1388 if(!this->isAlive() || !pVictim
->isAlive())
1391 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1395 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1399 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1401 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1404 // Calculate absorb & resists
1408 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1410 //No more damage left, target absorbed and/or resisted all damage
1411 if (damage
> absorb
+ resist
)
1412 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1415 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1418 HitInfo
|= HITINFO_ABSORB
;
1421 HitInfo
|= HITINFO_RESIST
;
1422 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1426 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1431 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1434 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1435 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1437 // Actual log sent to client
1438 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1441 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1442 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1446 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1447 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1450 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1456 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1459 if(cleanDamage
.damage
)
1460 // Rage from damage received.
1461 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1462 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1468 void Unit::HandleEmoteCommand(uint32 anim_id
)
1470 WorldPacket
data( SMSG_EMOTE
, 12 );
1471 data
<< anim_id
<< GetGUID();
1472 WPAssert(data
.size() == 12);
1474 SendMessageToSet(&data
, true);
1477 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1479 uint32 newdamage
= 0;
1480 float armor
= pVictim
->GetArmor();
1481 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1482 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1484 if (armor
<0.0f
) armor
=0.0f
;
1486 float tmpvalue
= 0.0f
;
1487 if(getLevel() <= 59) //Level 1-59
1488 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1489 else if(getLevel() < 70) //Level 60-69
1490 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1492 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1496 if(tmpvalue
> 0.75f
)
1498 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1500 return (newdamage
> 1) ? newdamage
: 1;
1503 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1505 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1508 // Magic damage, check for resists
1509 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1511 // Get base victim resistance for school
1512 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1513 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1514 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1516 tmpvalue2
*= (float)(0.15f
/ getLevel());
1517 if (tmpvalue2
< 0.0f
)
1519 if (tmpvalue2
> 0.75f
)
1521 uint32 ran
= urand(0, 100);
1522 uint32 faq
[4] = {24,6,4,6};
1525 for (uint8 i
= 0; i
< 4; i
++)
1527 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1533 if (damagetype
== DOT
&& m
== 4)
1534 *resist
+= uint32(damage
- 1);
1536 *resist
+= uint32(damage
* m
/ 4);
1537 if(*resist
> damage
)
1543 int32 RemainingDamage
= damage
- *resist
;
1545 // absorb without mana cost
1546 int32 reflectDamage
= 0;
1547 Aura
* reflectAura
= NULL
;
1548 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1549 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1553 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1557 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1559 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1561 if (pVictim
->GetHealth() <= RemainingDamage
)
1563 int32 chance
= (*i
)->GetModifier()->m_amount
;
1564 if (roll_chance_i(chance
))
1566 pVictim
->CastSpell(pVictim
,31231,true);
1567 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1569 // with health > 10% lost health until health==10%, in other case no losses
1570 uint32 health10
= pVictim
->GetMaxHealth()/10;
1571 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1577 int32 currentAbsorb
;
1580 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1582 if(Unit
* caster
= (*i
)->GetCaster())
1584 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1585 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1587 switch((*k
)->GetModifier()->m_miscvalue
)
1589 case 5065: // Rank 1
1590 case 5064: // Rank 2
1591 case 5063: // Rank 3
1592 case 5062: // Rank 4
1593 case 5061: // Rank 5
1595 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1596 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1598 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1611 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1613 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1614 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1615 next
= vSchoolAbsorb
.begin();
1619 currentAbsorb
= RemainingDamage
;
1620 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1623 RemainingDamage
-= currentAbsorb
;
1625 // do not cast spells while looping auras; auras can get invalid otherwise
1627 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1629 // absorb by mana cost
1630 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1631 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1635 // check damage school mask
1636 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1639 int32 currentAbsorb
;
1640 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1641 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1643 currentAbsorb
= RemainingDamage
;
1645 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1646 if(Player
*modOwner
= GetSpellModOwner())
1647 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1649 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1650 if (currentAbsorb
> maxAbsorb
)
1651 currentAbsorb
= maxAbsorb
;
1653 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1654 if((*i
)->GetModifier()->m_amount
<= 0)
1656 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1657 next
= vManaShield
.begin();
1660 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1661 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1663 RemainingDamage
-= currentAbsorb
;
1666 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1667 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1671 // check damage school mask
1672 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1675 // Damage can be splitted only if aura has an alive caster
1676 Unit
*caster
= (*i
)->GetCaster();
1677 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1680 int32 currentAbsorb
;
1681 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1682 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1684 currentAbsorb
= RemainingDamage
;
1686 RemainingDamage
-= currentAbsorb
;
1688 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1690 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1691 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1694 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1695 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1699 // check damage school mask
1700 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1703 // Damage can be splitted only if aura has an alive caster
1704 Unit
*caster
= (*i
)->GetCaster();
1705 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1708 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1710 RemainingDamage
-= splitted
;
1712 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1714 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1715 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1718 *absorb
= damage
- RemainingDamage
- *resist
;
1721 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
)
1723 MeleeHitOutcome outcome
;
1725 // If is casted Melee spell, calculate like physical
1727 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1729 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1731 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1732 pVictim
->AddThreat(this, 0.0f
);
1735 case MELEE_HIT_EVADE
:
1737 *hitInfo
|= HITINFO_MISS
;
1739 cleanDamage
->damage
= 0;
1742 case MELEE_HIT_MISS
:
1744 *hitInfo
|= HITINFO_MISS
;
1746 cleanDamage
->damage
= 0;
1747 if(GetTypeId()== TYPEID_PLAYER
)
1748 ((Player
*)this)->UpdateWeaponSkill(attType
);
1753 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1754 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1755 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1757 // -probability is between 0% and 40%
1759 float Probability
= 20;
1761 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1762 if( pVictim
->getLevel() < 30 )
1763 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1765 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1766 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1768 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1770 if(Probability
> 40.0f
)
1771 Probability
= 40.0f
;
1773 if(roll_chance_f(Probability
))
1774 CastSpell(pVictim
, 1604, true);
1777 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1778 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1780 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1782 // random durability for main hand weapon (ABSORB)
1783 if(damageAfterArmor
< *damage
)
1784 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1785 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1786 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1788 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1789 *damage
= damageAfterArmor
;
1792 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1793 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1795 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1796 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1800 case MELEE_HIT_BLOCK_CRIT
:
1801 case MELEE_HIT_CRIT
:
1803 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| HITINFO_UNK2
;
1807 crit_bonus
= *damage
;
1809 // Apply crit_damage bonus for melee spells
1812 if(Player
* modOwner
= GetSpellModOwner())
1813 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1815 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1816 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1817 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1818 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1819 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1822 *damage
+= crit_bonus
;
1824 uint32 resilienceReduction
= 0;
1826 if(attType
== RANGED_ATTACK
)
1828 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1829 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1830 // Resilience - reduce crit damage
1831 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1832 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1836 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1837 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1838 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1839 // Resilience - reduce crit damage
1840 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1841 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1844 *damage
-= resilienceReduction
;
1845 cleanDamage
->damage
+= resilienceReduction
;
1847 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1848 ((Player
*)this)->UpdateWeaponSkill(attType
);
1850 ModifyAuraState(AURA_STATE_CRIT
, true);
1851 StartReactiveTimer( REACTIVE_CRIT
);
1853 if(getClass()==CLASS_HUNTER
)
1855 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1856 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1859 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1861 *blocked_amount
= pVictim
->GetShieldBlockValue();
1863 if (pVictim
->GetUnitBlockChance())
1864 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1866 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1868 //Only set VICTIMSTATE_BLOCK on a full block
1869 if (*blocked_amount
>= uint32(*damage
))
1871 *victimState
= VICTIMSTATE_BLOCKS
;
1872 *blocked_amount
= uint32(*damage
);
1875 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1878 ((Player
*)pVictim
)->UpdateDefense();
1880 // random durability for main hand weapon (BLOCK)
1881 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1882 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1885 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1886 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1890 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1893 case MELEE_HIT_PARRY
:
1895 if(attType
== RANGED_ATTACK
) //range attack - no parry
1897 outcome
= MELEE_HIT_NORMAL
;
1901 cleanDamage
->damage
+= *damage
;
1903 *victimState
= VICTIMSTATE_PARRY
;
1905 // instant (maybe with small delay) counter attack
1907 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1908 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1910 // after parry nearest next attack time will reduced at %40 from full attack time.
1911 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1912 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1914 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1915 float percent60
= 3*percent20
;
1916 // set to 20% if in range 20%...20+40% of full time
1917 if(offtime
> percent20
&& offtime
<= percent60
)
1919 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1921 // decrease at %40 from full time
1922 else if(offtime
> percent60
)
1924 offtime
-= 2*percent20
;
1925 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1931 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1932 float percent60
= 3*percent20
;
1933 // set to 20% if in range 20%...20+40% of full time
1934 if(basetime
> percent20
&& basetime
<= percent60
)
1936 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1938 // decrease at %40 from full time
1939 else if(basetime
> percent60
)
1941 basetime
-= 2*percent20
;
1942 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1948 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1950 // Update victim defense ?
1951 ((Player
*)pVictim
)->UpdateDefense();
1953 // random durability for main hand weapon (PARRY)
1954 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1955 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1958 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1960 if (pVictim
->getClass() == CLASS_HUNTER
)
1962 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1963 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1967 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1968 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1971 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1974 case MELEE_HIT_DODGE
:
1976 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1978 outcome
= MELEE_HIT_NORMAL
;
1982 cleanDamage
->damage
+= *damage
;
1984 *victimState
= VICTIMSTATE_DODGE
;
1986 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1987 ((Player
*)pVictim
)->UpdateDefense();
1989 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1991 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1993 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1994 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1998 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
2000 ((Player
*)this)->AddComboPoints(pVictim
, 1);
2001 StartReactiveTimer( REACTIVE_OVERPOWER
);
2004 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2007 case MELEE_HIT_BLOCK
:
2009 *blocked_amount
= pVictim
->GetShieldBlockValue();
2011 if (pVictim
->GetUnitBlockChance())
2012 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2014 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2016 //Only set VICTIMSTATE_BLOCK on a full block
2017 if (*blocked_amount
>= uint32(*damage
))
2019 *victimState
= VICTIMSTATE_BLOCKS
;
2020 *blocked_amount
= uint32(*damage
);
2023 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2026 ((Player
*)pVictim
)->UpdateDefense();
2028 // random durability for main hand weapon (BLOCK)
2029 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2030 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2033 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2034 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2038 case MELEE_HIT_GLANCING
:
2040 float reducePercent
= 1.0f
; //damage factor
2042 // calculate base values and mods
2043 float baseLowEnd
= 1.3;
2044 float baseHighEnd
= 1.2;
2045 switch(getClass()) // lowering base values for casters
2057 float maxLowEnd
= 0.6;
2058 switch(getClass()) // upper for melee classes
2062 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2066 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2067 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2068 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2070 // apply max/min bounds
2071 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2073 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2076 if ( highEnd
< 0.2f
) //high end limits
2078 if ( highEnd
> 0.99f
)
2081 if(lowEnd
> highEnd
) // prevent negative range size
2084 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2086 *damage
= uint32(reducePercent
* *damage
);
2087 cleanDamage
->damage
+= *damage
;
2088 *hitInfo
|= HITINFO_GLANCING
;
2091 case MELEE_HIT_CRUSHING
:
2093 // 150% normal damage
2094 *damage
+= (*damage
/ 2);
2095 cleanDamage
->damage
= *damage
;
2096 *hitInfo
|= HITINFO_CRUSHING
;
2097 // TODO: victimState, victim animation?
2104 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2105 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2107 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2108 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2111 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2112 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2114 cleanDamage
->damage
+= *blocked_amount
;
2116 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2118 //*hitInfo = 0x00010020;
2119 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2121 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2125 // update at damage Judgement aura duration that applied by attacker at victim
2128 AuraMap
const& vAuras
= pVictim
->GetAuras();
2129 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2131 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2132 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2133 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2135 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2136 (*itr
).second
->SendAuraUpdate(false);
2141 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2143 // victim's damage shield
2144 // yet another hack to fix crashes related to the aura getting removed during iteration
2145 std::set
<Aura
*> alreadyDone
;
2146 uint32 removedAuras
= pVictim
->m_removedAuras
;
2147 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2148 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2151 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2153 alreadyDone
.insert(*i
);
2154 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2155 if (pVictim
->m_removedAuras
> removedAuras
)
2157 removedAuras
= pVictim
->m_removedAuras
;
2158 next
= vDamageShields
.begin();
2164 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2166 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2169 if (!pVictim
->isAlive())
2172 if(IsNonMeleeSpellCasted(false))
2176 if (attType
== BASE_ATTACK
)
2177 hitInfo
= HITINFO_NORMALSWING2
;
2178 else if (attType
== OFF_ATTACK
)
2179 hitInfo
= HITINFO_LEFTSWING
;
2181 return; // ignore ranaged case
2183 uint32 extraAttacks
= m_extraAttacks
;
2185 // melee attack spell casted at main hand attack only
2186 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2188 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2190 // not recent extra attack only at any non extra attack (melee spell case)
2191 if(!extra
&& extraAttacks
)
2193 while(m_extraAttacks
)
2195 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2196 if(m_extraAttacks
> 0)
2204 VictimState victimState
= VICTIMSTATE_NORMAL
;
2206 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2207 uint32 blocked_dmg
= 0;
2208 uint32 absorbed_dmg
= 0;
2209 uint32 resisted_dmg
= 0;
2211 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2213 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2215 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2217 // not recent extra attack only at any non extra attack (miss case)
2218 if(!extra
&& extraAttacks
)
2220 while(m_extraAttacks
)
2222 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2223 if(m_extraAttacks
> 0)
2231 uint32 damage
= CalculateDamage (attType
, false);
2233 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2235 if (hitInfo
& HITINFO_MISS
)
2237 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2241 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2243 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2244 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2248 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2250 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2252 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2253 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2257 if (GetTypeId() == TYPEID_PLAYER
)
2258 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2259 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2261 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2262 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2264 // extra attack only at any non extra attack (normal case)
2265 if(!extra
&& extraAttacks
)
2267 while(m_extraAttacks
)
2269 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2270 if(m_extraAttacks
> 0)
2276 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2278 // Miss chance based on melee
2279 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2281 // Critical hit chance
2282 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2283 // this is to avoid compiler issue when declaring variables inside if
2284 float block_chance
, parry_chance
, dodge_chance
;
2286 // cannot be dodged/parried/blocked
2287 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2289 block_chance
= 0.0f
;
2290 parry_chance
= 0.0f
;
2291 dodge_chance
= 0.0f
;
2295 // parry can be avoided only by some abilites
2296 parry_chance
= pVictim
->GetUnitParryChance();
2297 // block might be bypassed by it as well
2298 block_chance
= pVictim
->GetUnitBlockChance();
2299 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2300 dodge_chance
= pVictim
->GetUnitDodgeChance();
2303 // Only players can have Talent&Spell bonuses
2304 if (GetTypeId() == TYPEID_PLAYER
)
2306 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2307 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2309 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents fpr speed
2311 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2312 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2314 // can't be dodged rogue finishing move
2315 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2317 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2319 dodge_chance
= 0.0f
;
2328 if(Player
* modOwner
= GetSpellModOwner())
2329 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2331 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2333 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);
2336 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2338 // This is only wrapper
2340 // Miss chance based on melee
2341 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2343 // Critical hit chance
2344 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2346 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2347 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2348 float block_chance
= pVictim
->GetUnitBlockChance();
2349 float parry_chance
= pVictim
->GetUnitParryChance();
2351 // Useful if want to specify crit & miss chances for melee, else it could be removed
2352 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2354 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);
2357 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
2359 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2360 return MELEE_HIT_EVADE
;
2362 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2363 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2365 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2366 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2368 // bonus from skills is 0.04%
2369 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2370 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2371 int32 sum
= 0, tmp
= 0;
2372 int32 roll
= urand (0, 10000);
2374 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2375 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2376 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2380 if (tmp
> 0 && roll
< (sum
+= tmp
))
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2383 return MELEE_HIT_MISS
;
2386 // always crit against a sitting target (except 0 crit chance)
2387 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2389 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2390 return MELEE_HIT_CRIT
;
2395 // only players can't dodge if attacker is behind
2396 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2398 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2402 // Reduce dodge chance by attacker expertise rating
2403 if (GetTypeId() == TYPEID_PLAYER
)
2404 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2406 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2407 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2410 if ( (tmp
> 0) // check if unit _can_ dodge
2411 && ((tmp
-= skillBonus
) > 0)
2412 && roll
< (sum
+= tmp
))
2414 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2415 return MELEE_HIT_DODGE
;
2419 // parry & block chances
2421 // check if attack comes from behind, nobody can parry or block if attacker is behind
2422 if (!pVictim
->HasInArc(M_PI
,this))
2424 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2428 // Reduce parry chance by attacker expertise rating
2429 if (GetTypeId() == TYPEID_PLAYER
)
2430 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2432 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2434 int32 tmp
= int32(parry_chance
);
2435 if ( (tmp
> 0) // check if unit _can_ parry
2436 && ((tmp
-= skillBonus
) > 0)
2437 && (roll
< (sum
+= tmp
)))
2439 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2440 return MELEE_HIT_PARRY
;
2444 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2447 if ( (tmp
> 0) // check if unit _can_ block
2448 && ((tmp
-= skillBonus
) > 0)
2449 && (roll
< (sum
+= tmp
)))
2452 tmp
= crit_chance
+ skillBonus2
;
2453 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2455 if ( roll_chance_i(tmp
/100))
2457 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2458 return MELEE_HIT_BLOCK_CRIT
;
2461 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2462 return MELEE_HIT_BLOCK
;
2468 tmp
= crit_chance
+ skillBonus2
;
2470 if (tmp
> 0 && roll
< (sum
+= tmp
))
2472 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2473 return MELEE_HIT_CRIT
;
2476 // 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)
2477 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2478 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2479 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2480 getLevel() < pVictim
->getLevelForTarget(this) )
2482 // cap possible value (with bonuses > max skill)
2483 int32 skill
= attackerWeaponSkill
;
2484 int32 maxskill
= attackerMaxSkillValueForLevel
;
2485 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2487 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2488 tmp
= tmp
> 4000 ? 4000 : tmp
;
2489 if (roll
< (sum
+= tmp
))
2491 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2492 return MELEE_HIT_GLANCING
;
2496 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2498 // mobs can score crushing blows if they're 3 or more levels above victim
2499 // or when their weapon skill is 15 or more above victim's defense skill
2500 tmp
= victimDefenseSkill
;
2501 int32 tmpmax
= victimMaxSkillValueForLevel
;
2502 // having defense above your maximum (from items, talents etc.) has no effect
2503 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2504 // tmp = mob's level * 5 - player's current defense skill
2505 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2508 // add 2% chance per lacking skill point, min. is 15%
2509 tmp
= tmp
* 200 - 1500;
2510 if (roll
< (sum
+= tmp
))
2512 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2513 return MELEE_HIT_CRUSHING
;
2518 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2519 return MELEE_HIT_NORMAL
;
2522 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2524 float min_damage
, max_damage
;
2526 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2527 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2533 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2534 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2537 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2538 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2541 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2542 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2544 // Just for good manner
2552 if (min_damage
> max_damage
)
2554 std::swap(min_damage
,max_damage
);
2557 if(max_damage
== 0.0f
)
2560 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2563 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2565 if(spellProto
->spellLevel
<= 0)
2568 float LvlPenalty
= 0.0f
;
2570 if(spellProto
->spellLevel
< 20)
2571 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2572 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2573 if(LvlFactor
> 1.0f
)
2576 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2579 void Unit::SendAttackStart(Unit
* pVictim
)
2581 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2583 data
<< pVictim
->GetGUID();
2585 SendMessageToSet(&data
, true);
2586 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2589 void Unit::SendAttackStop(Unit
* victim
)
2594 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2595 data
.append(GetPackGUID());
2596 data
.append(victim
->GetPackGUID()); // can be 0x00...
2597 data
<< uint32(0); // can be 0x1
2598 SendMessageToSet(&data
, true);
2599 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2601 /*if(victim->GetTypeId() == TYPEID_UNIT)
2602 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2606 // Melee based spells can be miss, parry or dodge on this step
2607 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2608 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2610 // Calculate hit chance (more correct for chance mod)
2613 // PvP - PvE melee chances
2614 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2615 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2617 HitChance = 95 - leveldif;
2619 HitChance = 93 - (leveldif - 2) * lchance;
2621 // Hit chance depends from victim auras
2622 if(attType == RANGED_ATTACK)
2623 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2625 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2627 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2628 if(Player *modOwner = GetSpellModOwner())
2629 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2632 float miss_chance= 100.0f - HitChance;
2634 // Bonuses from attacker aura and ratings
2635 if (attType == RANGED_ATTACK)
2636 miss_chance -= m_modRangedHitChance;
2638 miss_chance -= m_modMeleeHitChance;
2640 // bonus from skills is 0.04%
2641 miss_chance -= skillDiff * 0.04f;
2643 // Limit miss chance from 0 to 60%
2644 if (miss_chance < 0.0f)
2646 if (miss_chance > 60.0f)
2651 // Melee based spells hit result calculations
2652 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2654 WeaponAttackType attType = BASE_ATTACK;
2656 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2657 attType = RANGED_ATTACK;
2659 // bonus from skills is 0.04% per skill Diff
2660 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2661 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2662 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2664 uint32 roll = urand (0, 10000);
2665 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2668 uint32 tmp = missChance;
2670 return SPELL_MISS_MISS;
2672 // Same spells cannot be parry/dodge
2673 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2674 return SPELL_MISS_NONE;
2676 // Ranged attack can`t miss too
2677 if (attType == RANGED_ATTACK)
2678 return SPELL_MISS_NONE;
2680 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2683 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2684 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2685 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2687 // Reduce dodge chance by attacker expertise rating
2688 if (GetTypeId() == TYPEID_PLAYER)
2689 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2690 if (dodgeChance < 0)
2693 // Can`t dodge from behind in PvP (but its possible in PvE)
2694 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2697 // Rogue talent`s cant be dodged
2698 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2699 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2701 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2703 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2713 return SPELL_MISS_DODGE;
2716 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2717 // Reduce parry chance by attacker expertise rating
2718 if (GetTypeId() == TYPEID_PLAYER)
2719 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2720 // Can`t parry from behind
2721 if (parryChance < 0 || attackFromBehind)
2726 return SPELL_MISS_PARRY;
2728 return SPELL_MISS_NONE;
2731 // TODO need use unit spell resistances in calculations
2732 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2734 // Can`t miss on dead target (on skinning for example)
2735 if (!pVictim
->isAlive())
2736 return SPELL_MISS_NONE
;
2738 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2739 // PvP - PvE spell misschances per leveldif > 2
2740 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2741 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2743 // Base hit chance from attacker and victim levels
2746 modHitChance
= 96 - leveldif
;
2748 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2750 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2751 if(Player
*modOwner
= GetSpellModOwner())
2752 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2753 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2754 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2755 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2756 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2757 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2758 if (IsAreaOfEffectSpell(spell
))
2759 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2760 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2761 if (IsDispelSpell(spell
))
2762 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2763 // Chance resist mechanic (select max value from every mechanic spell effect)
2764 int32 resist_mech
= 0;
2765 // Get effects mechanic and chance
2766 for(int eff
= 0; eff
< 3; ++eff
)
2768 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2771 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2772 if (resist_mech
< temp
)
2777 modHitChance
-=resist_mech
;
2779 // Chance resist debuff
2780 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2782 int32 HitChance
= modHitChance
* 100;
2783 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2784 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2786 // Decrease hit chance from victim rating bonus
2787 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2788 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2790 if (HitChance
< 100) HitChance
= 100;
2791 if (HitChance
> 9900) HitChance
= 9900;
2793 uint32 rand
= urand(0,10000);
2794 if (rand
> HitChance
)
2795 return SPELL_MISS_RESIST
;
2796 return SPELL_MISS_NONE
;
2799 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2801 // Return evade for units in evade mode
2802 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2803 return SPELL_MISS_EVADE
;
2805 // Check for immune (use charges)
2806 if (pVictim
->IsImmunedToSpell(spell
,true))
2807 return SPELL_MISS_IMMUNE
;
2809 // All positive spells can`t miss
2810 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2811 if (IsPositiveSpell(spell
->Id
))
2812 return SPELL_MISS_NONE
;
2814 // Check for immune (use charges)
2815 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2816 return SPELL_MISS_IMMUNE
;
2818 // Try victim reflect spell
2821 // specialized first
2822 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2823 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2825 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2827 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2828 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2830 if((*i
)->m_procCharges
> 0)
2832 --(*i
)->m_procCharges
;
2833 if((*i
)->m_procCharges
==0)
2834 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2836 return SPELL_MISS_REFLECT
;
2841 // generic reflection
2842 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2843 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2845 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2846 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2848 if((*i
)->m_procCharges
> 0)
2850 --(*i
)->m_procCharges
;
2851 if((*i
)->m_procCharges
==0)
2852 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2854 return SPELL_MISS_REFLECT
;
2859 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2860 for (int i
=0;i
<3;i
++)
2862 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2863 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2864 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2865 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2866 return SPELL_MISS_NONE
;
2869 // TODO need use this code for spell hit result calculation
2870 // now code commented for compotability
2871 switch (spell
->DmgClass
)
2873 case SPELL_DAMAGE_CLASS_RANGED
:
2874 case SPELL_DAMAGE_CLASS_MELEE
:
2875 // return MeleeSpellHitResult(pVictim, spell);
2876 return SPELL_MISS_NONE
;
2877 case SPELL_DAMAGE_CLASS_NONE
:
2878 case SPELL_DAMAGE_CLASS_MAGIC
:
2879 return MagicSpellHitResult(pVictim
, spell
);
2881 return SPELL_MISS_NONE
;
2884 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2889 // Base misschance 5%
2890 float misschance
= 5.0f
;
2892 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2893 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2895 bool isNormal
= false;
2896 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2898 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2904 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2914 // PvP : PvE melee misschances per leveldif > 2
2915 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2917 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2921 // Hit chance from attacker based on ratings and auras
2922 float m_modHitChance
;
2923 if (attType
== RANGED_ATTACK
)
2924 m_modHitChance
= m_modRangedHitChance
;
2926 m_modHitChance
= m_modMeleeHitChance
;
2929 misschance
+= (leveldif
- m_modHitChance
);
2931 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2933 // Hit chance for victim based on ratings
2934 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2936 if (attType
== RANGED_ATTACK
)
2937 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2939 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2942 // Modify miss chance by victim auras
2943 if(attType
== RANGED_ATTACK
)
2944 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2946 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2948 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2949 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2950 misschance
-= skillBonus
* 0.04f
;
2952 // Limit miss chance from 0 to 60%
2953 if ( misschance
< 0.0f
)
2955 if ( misschance
> 60.0f
)
2961 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2963 if(GetTypeId() == TYPEID_PLAYER
)
2965 // in PvP use full skill instead current skill value
2966 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2967 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2968 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2969 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2973 return GetUnitMeleeSkill(target
);
2976 float Unit::GetUnitDodgeChance() const
2978 if(hasUnitState(UNIT_STAT_STUNNED
))
2980 if( GetTypeId() == TYPEID_PLAYER
)
2981 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2984 if(((Creature
const*)this)->isTotem())
2989 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2990 return dodge
> 0.0f
? dodge
: 0.0f
;
2995 float Unit::GetUnitParryChance() const
2997 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3000 float chance
= 0.0f
;
3002 if(GetTypeId() == TYPEID_PLAYER
)
3004 Player
const* player
= (Player
const*)this;
3005 if(player
->CanParry() )
3007 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3009 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3012 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3015 else if(GetTypeId() == TYPEID_UNIT
)
3017 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3020 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3024 return chance
> 0.0f
? chance
: 0.0f
;
3027 float Unit::GetUnitBlockChance() const
3029 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3032 if(GetTypeId() == TYPEID_PLAYER
)
3034 Player
const* player
= (Player
const*)this;
3035 if(player
->CanBlock() )
3037 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3038 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3039 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3041 // is player but has no block ability or no not broken shield equiped
3046 if(((Creature
const*)this)->isTotem())
3051 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3052 return block
> 0.0f
? block
: 0.0f
;
3057 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3061 if(GetTypeId() == TYPEID_PLAYER
)
3066 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3069 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3072 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3074 // Just for good manner
3083 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3087 if(attackType
== RANGED_ATTACK
)
3088 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3090 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3092 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3094 // reduce crit chance from Rating for players
3095 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3097 if (attackType
==RANGED_ATTACK
)
3098 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3100 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3108 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3111 if(GetTypeId() == TYPEID_PLAYER
)
3113 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3115 // feral or unarmed skill only for base attack
3116 if(attType
!= BASE_ATTACK
&& !item
)
3119 if(((Player
*)this)->IsInFeralForm())
3120 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3122 // weaon skill or (unarmed for base attack)
3123 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3125 // in PvP use full skill instead current skill value
3126 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3127 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3128 : ((Player
*)this)->GetSkillValue(skill
);
3129 // Modify value from ratings
3130 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3133 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3134 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3135 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3139 value
= GetUnitMeleeSkill(target
);
3143 void Unit::_UpdateSpells( uint32 time
)
3145 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3146 _UpdateAutoRepeatSpell();
3148 // remove finished spells from current pointers
3149 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3151 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3153 m_currentSpells
[i
]->SetDeletable(true); // spell may be safely deleted now
3154 m_currentSpells
[i
] = NULL
; // remove pointer
3158 // TODO: Find a better way to prevent crash when multiple auras are removed.
3160 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3162 (*i
).second
->SetUpdated(false);
3164 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3170 // prevent double update
3171 if ((*i
).second
->IsUpdated())
3173 (*i
).second
->SetUpdated(true);
3174 (*i
).second
->Update( time
);
3175 // several auras can be deleted due to update
3178 if (m_Auras
.empty()) break;
3179 next
= m_Auras
.begin();
3185 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3189 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3204 if(!m_gameObj
.empty())
3206 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3207 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3210 //(*i)->Update( difftime );
3211 if( !(*ite1
)->isSpawned() )
3213 (*ite1
)->SetOwnerGUID(0);
3214 (*ite1
)->SetRespawnTime(0);
3216 dnext1
= m_gameObj
.erase(ite1
);
3224 void Unit::_UpdateAutoRepeatSpell()
3226 //check "realtime" interrupts
3227 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3229 // cancel wand shoot
3230 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3231 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3232 m_AutoRepeatFirstCast
= true;
3237 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3238 setAttackTimer(RANGED_ATTACK
,500);
3239 m_AutoRepeatFirstCast
= false;
3242 if (isAttackReady(RANGED_ATTACK
))
3244 // Check if able to cast
3245 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3247 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3252 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3253 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3255 // all went good, reset attack
3256 resetAttackTimer(RANGED_ATTACK
);
3260 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3262 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3264 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3266 pSpell
->SetDeletable(false); // spell will not be deleted until gone from current pointers
3267 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3269 // break same type spell if it is not delayed
3270 InterruptSpell(CSpellType
,false);
3272 // special breakage effects:
3275 case CURRENT_GENERIC_SPELL
:
3277 // generic spells always break channeled not delayed spells
3278 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3280 // autorepeat breaking
3281 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3283 // break autorepeat if not Auto Shot
3284 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3285 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3286 m_AutoRepeatFirstCast
= true;
3290 case CURRENT_CHANNELED_SPELL
:
3292 // channel spells always break generic non-delayed and any channeled spells
3293 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3294 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3296 // it also does break autorepeat if not Auto Shot
3297 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3298 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3299 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3302 case CURRENT_AUTOREPEAT_SPELL
:
3304 // only Auto Shoot does not break anything
3305 if (pSpell
->m_spellInfo
->Category
== 351)
3307 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3308 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3309 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3311 // special action: set first cast flag
3312 m_AutoRepeatFirstCast
= true;
3317 // other spell types don't break anything now
3321 // current spell (if it is still here) may be safely deleted now
3322 if (m_currentSpells
[CSpellType
])
3323 m_currentSpells
[CSpellType
]->SetDeletable(true);
3325 // set new current spell
3326 m_currentSpells
[CSpellType
] = pSpell
;
3329 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3331 assert(spellType
< CURRENT_MAX_SPELL
);
3333 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3335 // send autorepeat cancel message for autorepeat spells
3336 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3338 if(GetTypeId()==TYPEID_PLAYER
)
3339 ((Player
*)this)->SendAutoRepeatCancel();
3342 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3343 m_currentSpells
[spellType
]->cancel();
3344 m_currentSpells
[spellType
]->SetDeletable(true);
3345 m_currentSpells
[spellType
] = NULL
;
3349 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3351 // We don't do loop here to explicitly show that melee spell is excluded.
3352 // Maybe later some special spells will be excluded too.
3354 // generic spells are casted when they are not finished and not delayed
3355 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3356 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3357 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3360 // channeled spells may be delayed, but they are still considered casted
3361 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3362 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3365 // autorepeat spells may be finished or delayed, but they are still considered casted
3366 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3372 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3374 // generic spells are interrupted if they are not finished or delayed
3375 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3377 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3378 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3379 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3380 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetDeletable(true);
3381 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3384 // autorepeat spells are interrupted if they are not finished or delayed
3385 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3387 // send disable autorepeat packet in any case
3388 if(GetTypeId()==TYPEID_PLAYER
)
3389 ((Player
*)this)->SendAutoRepeatCancel();
3391 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3392 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3393 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3394 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetDeletable(true);
3395 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3398 // channeled spells are interrupted if they are not finished, even if they are delayed
3399 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3401 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3402 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3403 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetDeletable(true);
3404 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3408 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3410 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3411 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3412 return m_currentSpells
[i
];
3416 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3418 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3421 void Unit::SetInFront(Unit
const* target
)
3423 SetOrientation(GetAngle(target
));
3426 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3428 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3431 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3434 return c
->canSwim();
3436 return c
->canWalk() || c
->canFly();
3439 bool Unit::IsInWater() const
3441 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3444 bool Unit::IsUnderWater() const
3446 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3449 void Unit::DeMorph()
3451 SetDisplayId(GetNativeDisplayId());
3454 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3458 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3459 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3460 modifier
+= (*i
)->GetModifier()->m_amount
;
3465 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3467 float multipler
= 1.0f
;
3469 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3470 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3471 multipler
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3476 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3480 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3481 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3482 if ((*i
)->GetModifier()->m_amount
> modifier
)
3483 modifier
= (*i
)->GetModifier()->m_amount
;
3488 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3492 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3493 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3494 if ((*i
)->GetModifier()->m_amount
< modifier
)
3495 modifier
= (*i
)->GetModifier()->m_amount
;
3500 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3504 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3505 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3507 Modifier
* mod
= (*i
)->GetModifier();
3508 if (mod
->m_miscvalue
& misc_mask
)
3509 modifier
+= mod
->m_amount
;
3514 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3516 float multipler
= 1.0f
;
3518 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3519 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3521 Modifier
* mod
= (*i
)->GetModifier();
3522 if (mod
->m_miscvalue
& misc_mask
)
3523 multipler
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3528 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3532 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3533 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3535 Modifier
* mod
= (*i
)->GetModifier();
3536 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3537 modifier
= mod
->m_amount
;
3543 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3547 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3548 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3550 Modifier
* mod
= (*i
)->GetModifier();
3551 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3552 modifier
= mod
->m_amount
;
3558 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3562 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3563 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3565 Modifier
* mod
= (*i
)->GetModifier();
3566 if (mod
->m_miscvalue
== misc_value
)
3567 modifier
+= mod
->m_amount
;
3572 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3574 float multipler
= 1.0f
;
3576 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3577 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3579 Modifier
* mod
= (*i
)->GetModifier();
3580 if (mod
->m_miscvalue
== misc_value
)
3581 multipler
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3586 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3590 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3591 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3593 Modifier
* mod
= (*i
)->GetModifier();
3594 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3595 modifier
= mod
->m_amount
;
3601 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3605 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3606 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3608 Modifier
* mod
= (*i
)->GetModifier();
3609 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3610 modifier
= mod
->m_amount
;
3616 bool Unit::AddAura(Aura
*Aur
)
3618 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3619 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3620 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3626 if(Aur
->GetTarget() != this)
3628 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3629 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3630 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3635 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3637 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3638 AuraMap::iterator i
= m_Auras
.find( spair
);
3640 // take out same spell
3641 if (i
!= m_Auras
.end())
3643 // passive and persistent auras can stack with themselves any number of times
3644 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3646 // replace aura if next will > spell StackAmount
3647 if(aurSpellInfo
->StackAmount
)
3649 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3650 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3652 // if StackAmount==0 not allow auras from same caster
3655 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3657 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3659 // can be only single (this check done at _each_ aura add
3660 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3665 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3668 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3669 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3670 case SPELL_AURA_PERIODIC_LEECH
:
3671 case SPELL_AURA_PERIODIC_HEAL
:
3672 case SPELL_AURA_OBS_MOD_HEALTH
:
3673 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3674 case SPELL_AURA_PERIODIC_ENERGIZE
:
3675 case SPELL_AURA_OBS_MOD_MANA
:
3676 case SPELL_AURA_POWER_BURN_MANA
:
3678 default: // not allow
3679 // can be only single (this check done at _each_ aura add
3680 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3692 // passive auras stack with all (except passive spell proc auras)
3693 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3694 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3696 if (!RemoveNoStackAurasDueToAura(Aur
))
3699 return false; // couldnt remove conflicting aura with higher rank
3703 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3704 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3706 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3709 Unit
* caster
= Aur
->GetCaster();
3710 if(!caster
) // caster deleted and not required adding scAura
3713 bool restart
= false;
3714 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3715 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3717 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3718 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3720 if ((*itr
)->IsInUse())
3722 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());
3725 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3734 scAuras
.push_back(Aur
);
3740 // add aura, register in lists and arrays
3742 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3743 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3745 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3748 Aur
->ApplyModifier(true,true);
3749 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3753 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3755 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3758 AuraMap::iterator i
,next
;
3759 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3763 uint32 i_spellId
= (*i
).second
->GetId();
3764 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3766 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3768 RemoveAurasDueToSpell(i_spellId
);
3770 if( m_Auras
.empty() )
3773 next
= m_Auras
.begin();
3779 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3784 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3788 uint32 spellId
= Aur
->GetId();
3789 uint32 effIndex
= Aur
->GetEffIndex();
3791 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3793 AuraMap::iterator i
,next
;
3794 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3798 if (!(*i
).second
) continue;
3800 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3805 uint32 i_spellId
= i_spellProto
->Id
;
3807 if(IsPassiveSpell(i_spellId
))
3809 if(IsPassiveStackableSpell(i_spellId
))
3812 // passive non-stackable spells not stackable only with another rank of same spell
3813 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3817 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3819 if(i_spellId
== spellId
) continue;
3821 bool is_triggered_by_spell
= false;
3822 // prevent triggered aura of removing aura that triggered it
3823 for(int j
= 0; j
< 3; ++j
)
3824 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3825 is_triggered_by_spell
= true;
3826 if (is_triggered_by_spell
) continue;
3828 for(int j
= 0; j
< 3; ++j
)
3830 // prevent remove dummy triggered spells at next effect aura add
3831 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggred spell
3833 case SPELL_EFFECT_DUMMY
:
3836 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3841 if(is_triggered_by_spell
)
3844 // prevent remove form main spell by triggred passive spells
3845 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3847 case SPELL_AURA_MOD_SHAPESHIFT
:
3850 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3851 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3852 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3858 if(!is_triggered_by_spell
)
3860 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3862 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3864 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3866 // cannot remove higher rank
3867 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3868 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3871 // Its a parent aura (create this aura in ApplyModifier)
3872 if ((*i
).second
->IsInUse())
3874 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());
3877 RemoveAurasDueToSpell(i_spellId
);
3879 if( m_Auras
.empty() )
3882 next
= m_Auras
.begin();
3884 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3886 // Its a parent aura (create this aura in ApplyModifier)
3887 if ((*i
).second
->IsInUse())
3889 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());
3892 RemoveAurasDueToSpell(i_spellId
);
3894 if( m_Auras
.empty() )
3897 next
= m_Auras
.begin();
3899 // Potions stack aura by aura (elixirs/flask already checked)
3900 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3902 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3904 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3905 return false; // cannot remove higher rank
3907 // Its a parent aura (create this aura in ApplyModifier)
3908 if ((*i
).second
->IsInUse())
3910 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());
3922 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3924 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3925 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3927 if(iter
->second
!=except
)
3930 iter
= m_Auras
.lower_bound(spair
);
3937 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3939 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3941 Aura
*aur
= iter
->second
;
3942 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3944 // Custom dispel case
3945 // Unstable Affliction
3946 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3948 int32 damage
= aur
->GetModifier()->m_amount
*9;
3949 uint64 caster_guid
= aur
->GetCasterGUID();
3952 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3954 // backfire damage and silence
3955 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3957 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3960 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3967 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3969 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3971 Aura
*aur
= iter
->second
;
3972 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3974 int32 basePoints
= aur
->GetBasePoints();
3975 // construct the new aura for the attacker
3976 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3980 // set its duration and maximum duration
3981 // max duration 2 minutes (in msecs)
3982 int32 dur
= aur
->GetAuraDuration();
3983 const int32 max_dur
= 2*MINUTE
*1000;
3984 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3985 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3987 // add the new aura to stealer
3988 stealer
->AddAura(new_aur
);
3990 // Remove aura as dispel
3991 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3998 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4000 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4002 if (iter
->second
->GetId() == spellId
)
4003 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4009 void Unit::RemoveAurasWithDispelType( DispelType type
)
4011 // Create dispel mask by dispel type
4012 uint32 dispelMask
= GetDispellMask(type
);
4013 // Dispel all existing auras vs current dispell type
4014 AuraMap
& auras
= GetAuras();
4015 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4017 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4018 if( (1<<spell
->Dispel
) & dispelMask
)
4021 RemoveAurasDueToSpell(spell
->Id
);
4022 itr
= auras
.begin();
4029 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4031 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4032 if(iter
!= m_Auras
.end())
4036 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4038 for (int i
= 0; i
< 3; ++i
)
4039 RemoveAura(spellId
,i
,except
);
4042 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4044 for (int k
=0; k
< 3; ++k
)
4046 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4047 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4049 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4052 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4060 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4062 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4064 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4071 void Unit::RemoveNotOwnSingleTargetAuras()
4073 // single target auras from other casters
4074 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4076 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4082 // single target auras at other targets
4083 AuraList
& scAuras
= GetSingleCastAuras();
4084 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4087 if (aura
->GetTarget()!=this)
4089 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4090 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4091 iter
= scAuras
.begin();
4099 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4101 if (IsSingleTargetSpell((*i
).second
->GetSpellProto()))
4103 if(Unit
* caster
= (*i
).second
->GetCaster())
4105 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4106 scAuras
.remove((*i
).second
);
4110 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4115 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4117 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
4120 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4121 Aura
* Aur
= i
->second
;
4123 Aur
->SetRemoveMode(mode
);
4124 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4125 // remove aura from list before to prevent deleting it before
4127 ++m_removedAuras
; // internal count used by unit update
4129 // Status unsummoned at aura remove
4130 Totem
* statue
= NULL
;
4131 if(IsChanneledSpell(Aur
->GetSpellProto()))
4132 if(Unit
* caster
= Aur
->GetCaster())
4133 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4134 statue
= ((Totem
*)caster
);
4136 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4137 Aur
->ApplyModifier(false,true);
4144 // only way correctly remove all auras from list
4145 if( m_Auras
.empty() )
4148 i
= m_Auras
.begin();
4151 void Unit::RemoveAllAuras()
4153 while (!m_Auras
.empty())
4155 AuraMap::iterator iter
= m_Auras
.begin();
4160 void Unit::RemoveAllAurasOnDeath()
4162 // used just after dieing to remove all visible auras
4163 // and disable the mods for the passive ones
4164 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4166 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4167 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4173 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4175 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4176 if (iter
!= m_Auras
.end())
4178 if (iter
->second
->GetAuraDuration() < delaytime
)
4179 iter
->second
->SetAuraDuration(0);
4181 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4182 iter
->second
->SendAuraUpdate(false);
4183 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4187 void Unit::_RemoveAllAuraMods()
4189 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4191 (*i
).second
->ApplyModifier(false);
4195 void Unit::_ApplyAllAuraMods()
4197 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4199 (*i
).second
->ApplyModifier(true);
4203 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4205 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4206 if (iter
!= m_Auras
.end())
4207 return iter
->second
;
4211 void Unit::AddDynObject(DynamicObject
* dynObj
)
4213 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4216 void Unit::RemoveDynObject(uint32 spellid
)
4218 if(m_dynObjGUIDs
.empty())
4220 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4222 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4225 i
= m_dynObjGUIDs
.erase(i
);
4227 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4230 i
= m_dynObjGUIDs
.erase(i
);
4237 void Unit::RemoveAllDynObjects()
4239 while(!m_dynObjGUIDs
.empty())
4241 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4244 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4248 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4250 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4252 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4255 i
= m_dynObjGUIDs
.erase(i
);
4259 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4266 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4268 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4270 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4273 i
= m_dynObjGUIDs
.erase(i
);
4277 if (dynObj
->GetSpellId() == spellId
)
4284 void Unit::AddGameObject(GameObject
* gameObj
)
4286 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4287 m_gameObj
.push_back(gameObj
);
4288 gameObj
->SetOwnerGUID(GetGUID());
4291 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4293 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4295 // GO created by some spell
4296 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4298 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4299 // Need activate spell use for owner
4300 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4301 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4303 gameObj
->SetOwnerGUID(0);
4304 m_gameObj
.remove(gameObj
);
4307 gameObj
->SetRespawnTime(0);
4312 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4314 if(m_gameObj
.empty())
4316 std::list
<GameObject
*>::iterator i
, next
;
4317 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4320 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4322 (*i
)->SetOwnerGUID(0);
4325 (*i
)->SetRespawnTime(0);
4329 next
= m_gameObj
.erase(i
);
4336 void Unit::RemoveAllGameObjects()
4338 // remove references to unit
4339 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4341 (*i
)->SetOwnerGUID(0);
4342 (*i
)->SetRespawnTime(0);
4344 i
= m_gameObj
.erase(i
);
4348 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4350 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4351 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4352 data
.append(target
->GetPackGUID());
4353 data
.append(GetPackGUID());
4354 data
<< uint32(SpellID
);
4355 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4356 data
<< uint32(0); // wotlk
4357 data
<< uint8(damageSchoolMask
); // spell school
4358 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4359 data
<< uint32(Resist
); // resist
4360 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
4361 data
<< uint8(0); // unk isFromAura
4362 data
<< uint32(Blocked
); // blocked
4363 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4364 data
<< uint8(0); // isDebug?
4365 SendMessageToSet( &data
, true );
4368 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4370 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4371 data
<< uint32(spellID
);
4372 data
<< uint64(GetGUID());
4373 data
<< uint8(0); // can be 0 or 1
4374 data
<< uint32(1); // target count
4375 // for(i = 0; i < target count; ++i)
4376 data
<< uint64(target
->GetGUID()); // target GUID
4377 data
<< uint8(missInfo
);
4379 SendMessageToSet(&data
, true);
4382 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4384 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4386 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4387 data
<< uint32(HitInfo
); // flags
4388 data
.append(GetPackGUID());
4389 data
.append(target
->GetPackGUID());
4390 data
<< uint32(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);// damage
4391 data
<< uint32(0); // overkill value
4393 data
<< (uint8
)SwingType
; // count?
4395 // for(i = 0; i < SwingType; ++i)
4396 data
<< (uint32
)damageSchoolMask
;
4397 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4398 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4401 if(HitInfo
& (HITINFO_ABSORB
| HITINFO_ABSORB2
))
4403 // for(i = 0; i < SwingType; ++i)
4404 data
<< uint32(AbsorbDamage
);
4408 if(HitInfo
& (HITINFO_RESIST
| HITINFO_RESIST2
))
4410 // for(i = 0; i < SwingType; ++i)
4411 data
<< uint32(Resist
);
4415 data
<< (uint8
)TargetState
;
4419 if(HitInfo
& HITINFO_BLOCK
)
4421 data
<< uint32(BlockedAmount
);
4424 if(HitInfo
& HITINFO_UNK3
)
4429 if(HitInfo
& HITINFO_UNK1
)
4440 for(uint8 i
= 0; i
< 5; ++i
)
4448 SendMessageToSet( &data
, true );
4451 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4453 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4455 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4457 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4458 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
4459 // That is the question though if it's fully correct
4460 if(procSpell
&& !isTriggeredSpell
)
4462 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4464 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4465 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4466 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4467 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4468 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4470 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4472 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4473 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4474 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4475 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4476 attType
= RANGED_ATTACK
;
4479 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4480 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4482 // Not much to do if no flags are set.
4485 // procces 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
4486 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4487 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4490 // Now go on with a victim's events'n'auras
4491 // Not much to do if no flags are set or there is no victim
4492 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4494 // procces 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
4495 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4496 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4500 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4505 uint32 procAttacker
= PROC_FLAG_NONE
;
4506 uint32 procVictim
= PROC_FLAG_NONE
;
4510 case MELEE_HIT_EVADE
:
4512 case MELEE_HIT_MISS
:
4513 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4515 procAttacker
= PROC_FLAG_MISS
;
4518 case MELEE_HIT_BLOCK_CRIT
:
4519 case MELEE_HIT_CRIT
:
4520 if(spellCasted
&& attType
== BASE_ATTACK
)
4522 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4523 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4524 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4526 procVictim
|= PROC_FLAG_BLOCK
;
4527 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4530 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4532 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4533 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4537 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4538 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4541 case MELEE_HIT_PARRY
:
4542 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4543 procVictim
= PROC_FLAG_PARRY
;
4545 case MELEE_HIT_BLOCK
:
4546 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4547 procVictim
= PROC_FLAG_BLOCK
;
4549 case MELEE_HIT_DODGE
:
4550 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4551 procVictim
= PROC_FLAG_DODGE
;
4553 case MELEE_HIT_CRUSHING
:
4554 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4556 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4557 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4561 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4562 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4566 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4568 procAttacker
= PROC_FLAG_HIT_MELEE
;
4569 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4573 procAttacker
= PROC_FLAG_HIT_RANGED
;
4574 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4580 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4582 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4583 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4586 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, SpellEntry
const *hasteSpell
, uint32
/*effIndex*/, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32
/*procFlag*/, uint32 cooldown
)
4588 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4589 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4591 uint32 triggered_spell_id
= 0;
4592 Unit
* target
= pVictim
;
4593 int32 basepoints0
= 0;
4595 switch(hasteSpell
->SpellFamilyName
)
4597 case SPELLFAMILY_ROGUE
:
4599 switch(hasteSpell
->Id
)
4605 target
= SelectNearbyTarget();
4608 basepoints0
= damage
;
4609 triggered_spell_id
= 22482;
4617 // processed charge only counting case
4618 if(!triggered_spell_id
)
4621 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4625 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4630 if(!target
|| target
!=this && !target
->isAlive())
4633 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4637 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4639 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4641 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4642 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4647 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, SpellEntry
const *dummySpell
, uint32 effIndex
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4649 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4650 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4652 uint32 triggered_spell_id
= 0;
4653 Unit
* target
= pVictim
;
4654 int32 basepoints0
= 0;
4656 switch(dummySpell
->SpellFamilyName
)
4658 case SPELLFAMILY_GENERIC
:
4660 switch (dummySpell
->Id
)
4666 // prevent damage back from weapon special attacks
4667 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4670 // return damage % to attacker but < 50% own total health
4671 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4672 if(basepoints0
> GetMaxHealth()/2)
4673 basepoints0
= GetMaxHealth()/2;
4675 triggered_spell_id
= 25997;
4683 // prevent chain of triggred spell from same triggred spell
4684 if(procSpell
&& procSpell
->Id
==26654)
4687 target
= SelectNearbyTarget();
4691 triggered_spell_id
= 26654;
4697 if (!procSpell
|| procSpell
->Id
== 24659)
4699 // Need remove one 24659 aura
4700 RemoveSingleAuraFromStack(24659, 0);
4701 RemoveSingleAuraFromStack(24659, 1);
4704 // Restless Strength
4707 // Need remove one 24662 aura
4708 RemoveSingleAuraFromStack(24662, 0);
4711 // Adaptive Warding (Frostfire Regalia set)
4719 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4720 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4722 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4724 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4734 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4736 case SPELL_SCHOOL_NORMAL
:
4737 case SPELL_SCHOOL_HOLY
:
4738 return false; // ignored
4739 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4740 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4741 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4742 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4743 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4751 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4759 for(int j
= 0; j
< 3; ++j
)
4761 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4770 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4772 case SPELL_SCHOOL_NORMAL
:
4773 return false; // ignore
4774 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4775 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4776 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4777 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4778 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4779 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4787 // Mana Leech (Passive) (Priest Pet Aura)
4791 target
= GetOwner();
4795 basepoints0
= int32(damage
* 2.5f
); // manaregen
4796 triggered_spell_id
= 34650;
4802 // Cast finish spell at last charge
4803 if (triggeredByAura
->m_procCharges
> 1)
4807 triggered_spell_id
= 33494;
4810 // Twisted Reflection (boss spell)
4812 triggered_spell_id
= 21064;
4814 // Vampiric Aura (boss spell)
4817 basepoints0
= 3 * damage
; // 300%
4818 if (basepoints0
< 0)
4821 triggered_spell_id
= 31285;
4825 // Aura of Madness (Darkmoon Card: Madness trinket)
4826 //=====================================================
4827 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4828 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4829 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4830 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4831 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4832 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4833 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4834 // 41011 Martyr Complex: +35 stamina (All classes)
4835 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4836 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4839 if(GetTypeId() != TYPEID_PLAYER
)
4842 // Select class defined buff
4845 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4846 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4848 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4849 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4852 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4853 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4855 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4856 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4859 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4860 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4861 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4862 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4864 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4865 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4868 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4870 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4871 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4879 if (roll_chance_i(10))
4880 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4884 // TODO: need find item for aura and triggered spells
4885 // Sunwell Exalted Caster Neck (??? neck)
4886 // cast ??? Light's Wrath if Exalted by Aldor
4887 // cast ??? Arcane Bolt if Exalted by Scryers*/
4889 return false; // disable for while
4892 if(GetTypeId() != TYPEID_PLAYER)
4895 // Get Aldor reputation rank
4896 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4899 triggered_spell_id = ???
4902 // Get Scryers reputation rank
4903 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4905 triggered_spell_id = ???
4910 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4911 // cast 45479 Light's Wrath if Exalted by Aldor
4912 // cast 45429 Arcane Bolt if Exalted by Scryers
4915 if(GetTypeId() != TYPEID_PLAYER
)
4918 // Get Aldor reputation rank
4919 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4922 triggered_spell_id
= 45479;
4925 // Get Scryers reputation rank
4926 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4928 triggered_spell_id
= 45429;
4933 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4934 // cast 45480 Light's Strength if Exalted by Aldor
4935 // cast 45428 Arcane Strike if Exalted by Scryers
4938 if(GetTypeId() != TYPEID_PLAYER
)
4941 // Get Aldor reputation rank
4942 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4945 triggered_spell_id
= 45480;
4948 // Get Scryers reputation rank
4949 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4951 triggered_spell_id
= 45428;
4956 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4957 // cast 45431 Arcane Insight if Exalted by Aldor
4958 // cast 45432 Light's Ward if Exalted by Scryers
4961 if(GetTypeId() != TYPEID_PLAYER
)
4964 // Get Aldor reputation rank
4965 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4968 triggered_spell_id
= 45432;
4971 // Get Scryers reputation rank
4972 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4975 triggered_spell_id
= 45431;
4980 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4981 // cast 45478 Light's Salvation if Exalted by Aldor
4982 // cast 45430 Arcane Surge if Exalted by Scryers
4985 if(GetTypeId() != TYPEID_PLAYER
)
4988 // Get Aldor reputation rank
4989 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4992 triggered_spell_id
= 45478;
4995 // Get Scryers reputation rank
4996 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4998 triggered_spell_id
= 45430;
5006 case SPELLFAMILY_MAGE
:
5009 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5011 if (getPowerType() != POWER_MANA
)
5015 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5017 triggered_spell_id
= 29442;
5020 // Master of Elements
5021 if (dummySpell
->SpellIconID
== 1920)
5027 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5028 if( basepoints0
<=0 )
5032 triggered_spell_id
= 29077;
5035 switch(dummySpell
->Id
)
5044 switch (dummySpell
->Id
)
5046 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5047 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5048 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5049 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5050 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5052 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5056 triggered_spell_id
= 12654;
5062 //last charge and crit
5063 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5065 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5066 return true; // charge counting (will removed)
5069 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5070 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5075 case SPELLFAMILY_WARRIOR
:
5078 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5080 // check attack comes not from behind
5081 if (!HasInArc(M_PI
, pVictim
))
5084 triggered_spell_id
= 22858;
5089 case SPELLFAMILY_WARLOCK
:
5091 // Seed of Corruption
5092 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5094 Modifier
* mod
= triggeredByAura
->GetModifier();
5095 // if damage is more than need or target die from damage deal finish spell
5096 // FIX ME: not triggered currently at death
5097 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5099 // remember guid before aura delete
5100 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5102 // Remove aura (before cast for prevent infinite loop handlers)
5103 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5105 // Cast finish spell (triggeredByAura already not exist!)
5106 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5107 return true; // no hidden cooldown
5111 mod
->m_amount
-=damage
;
5114 // Seed of Corruption (Mobs cast) - no die req
5115 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5117 Modifier
* mod
= triggeredByAura
->GetModifier();
5118 // if damage is more than need deal finish spell
5119 if( mod
->m_amount
<= damage
)
5121 // remember guid before aura delete
5122 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5124 // Remove aura (before cast for prevent infinite loop handlers)
5125 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5127 // Cast finish spell (triggeredByAura already not exist!)
5128 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5129 return true; // no hidden cooldown
5132 mod
->m_amount
-=damage
;
5135 switch(dummySpell
->Id
)
5142 triggered_spell_id
= 17941;
5151 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5153 triggered_spell_id
= 30294;
5156 // Shadowflame (Voidheart Raiment set bonus)
5159 triggered_spell_id
= 37379;
5162 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5170 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5171 triggered_spell_id
= 37382;
5174 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5177 triggered_spell_id
= 37378;
5183 case SPELLFAMILY_PRIEST
:
5186 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5188 if(!pVictim
|| !pVictim
->isAlive())
5191 // pVictim is caster of aura
5192 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5196 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5197 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5198 return true; // no hidden cooldown
5200 switch(dummySpell
->Id
)
5205 if(!pVictim
|| !pVictim
->isAlive())
5208 // pVictim is caster of aura
5209 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5213 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5214 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5215 return true; // no hidden cooldown
5217 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5220 // Shadow Word: Pain
5221 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5222 triggered_spell_id
= 40441;
5224 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5225 triggered_spell_id
= 40440;
5232 // Oracle Healing Bonus ("Garments of the Oracle" set)
5236 basepoints0
= int32(damage
* 10/100);
5238 triggered_spell_id
= 26170;
5241 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5244 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5248 basepoints0
= int32(damage
* 2 / 100);
5250 triggered_spell_id
= 39373;
5253 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5256 triggered_spell_id
= 28810;
5262 case SPELLFAMILY_DRUID
:
5264 switch(dummySpell
->Id
)
5266 // Healing Touch (Dreamwalker Raiment set)
5270 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5272 triggered_spell_id
= 28742;
5275 // Healing Touch Refund (Idol of Longevity trinket)
5279 triggered_spell_id
= 28848;
5282 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5287 triggered_spell_id
= 37238;
5290 // Druid Tier 6 Trinket
5296 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5298 triggered_spell_id
= 40445;
5302 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5304 triggered_spell_id
= 40446;
5307 // Mangle (cat/bear)
5308 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5310 triggered_spell_id
= 40452;
5316 if (!roll_chance_f(chance
))
5325 // Deadly Interrupt Effect
5326 triggered_spell_id
= 32747;
5332 case SPELLFAMILY_ROGUE
:
5334 switch(dummySpell
->Id
)
5336 // Deadly Throw Interrupt
5339 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5343 triggered_spell_id
= 32747;
5348 if( dummySpell
->SpellIconID
== 2116 )
5353 // only rogue's finishing moves (maybe need additional checks)
5354 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5355 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5359 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5360 if(basepoints0
<= 0)
5364 triggered_spell_id
= 31663;
5369 case SPELLFAMILY_HUNTER
:
5371 // Thrill of the Hunt
5372 if ( dummySpell
->SpellIconID
== 2236 )
5378 basepoints0
= procSpell
->manaCost
* 40/100;
5379 if(basepoints0
<= 0)
5383 triggered_spell_id
= 34720;
5388 case SPELLFAMILY_PALADIN
:
5390 // Seal of Righteousness - melee proc dummy
5391 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5393 if(GetTypeId() != TYPEID_PLAYER
)
5397 switch (triggeredByAura
->GetId())
5399 case 21084: spellId
= 25742; break; // Rank 1
5400 case 20287: spellId
= 25740; break; // Rank 2
5401 case 20288: spellId
= 25739; break; // Rank 3
5402 case 20289: spellId
= 25738; break; // Rank 4
5403 case 20290: spellId
= 25737; break; // Rank 5
5404 case 20291: spellId
= 25736; break; // Rank 6
5405 case 20292: spellId
= 25735; break; // Rank 7
5406 case 20293: spellId
= 25713; break; // Rank 8
5407 case 27155: spellId
= 27156; break; // Rank 9
5409 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5412 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5413 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5415 float damageBasePoints
;
5416 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5418 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5420 // one hand weapon/no weapon
5421 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5423 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5425 // apply damage bonuses manually
5426 if(damagePoint
>= 0)
5427 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5429 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5430 return true; // no hidden cooldown
5432 // Seal of Blood do damage trigger
5433 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5435 switch(triggeredByAura
->GetEffIndex())
5438 // prevent chain triggering
5439 if(procSpell
&& procSpell
->Id
==31893 )
5442 triggered_spell_id
= 31893;
5447 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5449 triggered_spell_id
= 32221;
5455 switch(dummySpell
->Id
)
5457 // Holy Power (Redemption Armor set)
5463 // Set class defined buff
5464 switch (pVictim
->getClass())
5470 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5474 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5478 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5481 triggered_spell_id
= 28790; // Increases the friendly target's armor
5491 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5494 triggered_spell_id
= 31803;
5501 // if healed by another unit (pVictim)
5506 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5508 triggered_spell_id
= 31786;
5511 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5519 // Flash of light/Holy light
5520 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5522 triggered_spell_id
= 40471;
5526 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5528 triggered_spell_id
= 40472;
5534 if (!roll_chance_f(chance
))
5542 case SPELLFAMILY_SHAMAN
:
5544 switch(dummySpell
->Id
)
5546 // Totemic Power (The Earthshatterer set)
5552 // Set class defined buff
5553 switch (pVictim
->getClass())
5559 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5563 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5567 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5570 triggered_spell_id
= 28827; // Increases the friendly target's armor
5577 // Lesser Healing Wave (Totem of Flowing Water Relic)
5581 triggered_spell_id
= 28850;
5584 // Windfury Weapon (Passive) 1-5 Ranks
5587 if(GetTypeId()!=TYPEID_PLAYER
)
5590 if(!castItem
|| !castItem
->IsEquipped())
5593 // custom cooldown processing case
5594 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5598 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5600 case 283: spellId
= 33757; break; //1 Rank
5601 case 284: spellId
= 33756; break; //2 Rank
5602 case 525: spellId
= 33755; break; //3 Rank
5603 case 1669:spellId
= 33754; break; //4 Rank
5604 case 2636:spellId
= 33727; break; //5 Rank
5607 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5608 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5613 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5614 if(!windfurySpellEntry
)
5616 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5620 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5623 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5625 // Value gained from additional AP
5626 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5627 triggered_spell_id
= 33750;
5632 // Value gained from additional AP
5633 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5634 triggered_spell_id
= 25504;
5637 // apply cooldown before cast to prevent processing itself
5639 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5642 for ( uint32 i
= 0; i
<2; ++i
)
5643 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5647 // Shaman Tier 6 Trinket
5654 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5656 triggered_spell_id
= 40465; // Lightning Bolt
5659 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5661 triggered_spell_id
= 40465; // Lesser Healing Wave
5664 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5666 triggered_spell_id
= 40466; // Stormstrike
5672 if (!roll_chance_f(chance
))
5681 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5683 if(GetTypeId() != TYPEID_PLAYER
)
5687 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5689 triggered_spell_id
= 379;
5692 // Lightning Overload
5693 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5695 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5698 // custom cooldown processing case
5699 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5703 // Every Lightning Bolt and Chain Lightning spell have dublicate vs half damage and zero cost
5704 switch (procSpell
->Id
)
5707 case 403: spellId
= 45284; break; // Rank 1
5708 case 529: spellId
= 45286; break; // Rank 2
5709 case 548: spellId
= 45287; break; // Rank 3
5710 case 915: spellId
= 45288; break; // Rank 4
5711 case 943: spellId
= 45289; break; // Rank 5
5712 case 6041: spellId
= 45290; break; // Rank 6
5713 case 10391: spellId
= 45291; break; // Rank 7
5714 case 10392: spellId
= 45292; break; // Rank 8
5715 case 15207: spellId
= 45293; break; // Rank 9
5716 case 15208: spellId
= 45294; break; // Rank 10
5717 case 25448: spellId
= 45295; break; // Rank 11
5718 case 25449: spellId
= 45296; break; // Rank 12
5720 case 421: spellId
= 45297; break; // Rank 1
5721 case 930: spellId
= 45298; break; // Rank 2
5722 case 2860: spellId
= 45299; break; // Rank 3
5723 case 10605: spellId
= 45300; break; // Rank 4
5724 case 25439: spellId
= 45301; break; // Rank 5
5725 case 25442: spellId
= 45302; break; // Rank 6
5727 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5730 // No thread generated mod
5731 SpellModifier
*mod
= new SpellModifier
;
5732 mod
->op
= SPELLMOD_THREAT
;
5734 mod
->type
= SPELLMOD_PCT
;
5735 mod
->spellId
= dummySpell
->Id
;
5737 mod
->lastAffected
= NULL
;
5738 mod
->mask
= 0x0000000000000003LL
;
5740 ((Player
*)this)->AddSpellMod(mod
, true);
5742 // Remove cooldown (Chain Lightning - have Category Recovery time)
5743 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5744 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5746 // Hmmm.. in most case spells alredy set half basepoints but...
5747 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5749 // 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.
5750 // So - no add changes :)
5751 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5753 ((Player
*)this)->AddSpellMod(mod
, false);
5755 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5756 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5766 // processed charge only counting case
5767 if(!triggered_spell_id
)
5770 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5774 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5779 if(!target
|| target
!=this && !target
->isAlive())
5782 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5786 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5788 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5790 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5791 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5796 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5798 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5800 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5801 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5803 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5804 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5805 int32 basepoints0
= 0;
5807 switch(auraSpellInfo
->SpellFamilyName
)
5809 case SPELLFAMILY_GENERIC
:
5811 switch(auraSpellInfo
->Id
)
5813 // Aegis of Preservation
5815 //Aegis Heal (instead non-existed triggered spell)
5816 triggered_spell_id
= 23781;
5819 // Elune's Touch (moonkin mana restore)
5822 // Elune's Touch (instead non-existed triggered spell)
5823 triggered_spell_id
= 33926;
5824 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5831 // only for cast with mana price
5832 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5834 break; // fall through to normal cast
5839 // at melee hit call std triggered spell
5840 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5841 break; // fall through to normal cast
5843 // Mark of Conquest - else (at range hit) called custom case
5844 triggered_spell_id
= 39557;
5850 return true; // nothing to do
5851 // Forgotten Knowledge (Blade of Wizardry)
5853 // only for harmful enemy targeted spell
5854 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5856 break; // fall through to normal cast
5857 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5860 // proc only at non-crit hits
5861 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5863 break; // fall through to normal cast
5865 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5871 //only periodic damage can trigger spell
5873 for(int j
= 0; j
< 3; ++j
)
5875 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5876 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5877 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5886 break; // fall through to normal cast
5888 // Evasive Maneuvers (Commendation of Kael'thas)
5891 // damage taken that reduces below 35% health
5892 // does NOT mean you must have been >= 35% before
5893 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5895 break; // fall through to normal cast
5899 switch(triggered_spell_id
)
5904 // applied only for main target
5905 if(!pVictim
|| pVictim
!= getVictim())
5908 // continue normal case
5911 // Shamanistic Rage triggered spell
5913 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5918 case SPELLFAMILY_MAGE
:
5920 switch(auraSpellInfo
->SpellIconID
)
5924 //Blazing Speed (instead non-existed triggered spell)
5925 triggered_spell_id
= 31643;
5929 switch(auraSpellInfo
->Id
)
5931 // Persistent Shield (Scarab Brooch)
5933 basepoints0
= int32(damage
* 0.15f
);
5938 case SPELLFAMILY_WARRIOR
:
5941 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5943 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5944 //and effect[1]==TriggerSpell
5945 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5947 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5950 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5951 break; // fall through to normal cast
5955 case SPELLFAMILY_WARLOCK
:
5958 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5960 // last case for Hellfire that damage caster also but don't must stun caster
5961 if( pVictim
== this )
5966 switch (triggeredByAura
->GetId())
5968 case 18096: chance
= 13.0f
; break;
5969 case 18073: chance
= 26.0f
; break;
5971 if (!roll_chance_f(chance
))
5974 // Pyroclasm (instead non-existed triggered spell)
5975 triggered_spell_id
= 18093;
5980 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5983 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5984 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5986 //Improved Drain Soul
5987 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5989 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5990 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5993 triggered_spell_id
= 18371;
6001 break; // fall through to normal cast
6005 case SPELLFAMILY_PRIEST
:
6008 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6010 switch (triggeredByAura
->GetSpellProto()->Id
)
6012 case 27811: triggered_spell_id
= 27813; break;
6013 case 27815: triggered_spell_id
= 27817; break;
6014 case 27816: triggered_spell_id
= 27818; break;
6016 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6020 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6021 basepoints0
= heal_amount
/3;
6026 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
[0]==7958)
6028 switch(triggeredByAura
->GetSpellProto()->Id
)
6031 triggered_spell_id
= 28377; break; // Rank 1
6033 triggered_spell_id
= 28378; break; // Rank 2
6035 triggered_spell_id
= 28379; break; // Rank 3
6037 triggered_spell_id
= 28380; break; // Rank 4
6039 triggered_spell_id
= 28381; break; // Rank 5
6041 triggered_spell_id
= 28382; break; // Rank 6
6043 triggered_spell_id
= 28385; break; // Rank 7
6045 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6053 case SPELLFAMILY_DRUID
:
6055 switch(auraSpellInfo
->Id
)
6057 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6060 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6062 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6063 triggered_spell_id
= 34299;
6066 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6073 triggered_spell_id
=37340; break;// Ursine Blessing
6075 triggered_spell_id
=37341; break;// Feline Blessing
6077 triggered_spell_id
=37342; break;// Slyvan Blessing
6079 triggered_spell_id
=37343; break;// Lunar Blessing
6081 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6092 case SPELLFAMILY_ROGUE
:
6094 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6096 switch(auraSpellInfo
->SpellIconID
)
6101 // skip non offhand attacks
6102 if(attackType
!=OFF_ATTACK
)
6104 break; // fall through to normal cast
6110 case SPELLFAMILY_PALADIN
:
6112 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6114 switch(auraSpellInfo
->Id
)
6116 // Lightning Capacitor
6119 // trinket ProcTriggerSpell but for safe checks for player
6120 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6123 if(((Player
*)this)->HasSpellCooldown(37657))
6127 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6128 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6129 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6133 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6134 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6135 if((*itr
)->GetId()==37658)
6138 // release at 3 aura in stack
6140 return true; // main triggered spell casted anyway
6142 RemoveAurasDueToSpell(37658);
6143 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6148 // Healing Trance (instead non-existed triggered spell)
6149 triggered_spell_id
= 37706;
6152 // HoTs on Heals (Fel Reaver's Piston trinket)
6155 // at direct heal effect
6156 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6159 // single proc at time
6160 AuraList
const& scAuras
= GetSingleCastAuras();
6161 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6162 if((*itr
)->GetId()==triggered_spell_id
)
6165 // positive cast at victim instead self
6170 switch(auraSpellInfo
->SpellIconID
)
6174 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6182 // procspell is triggered spell but we need mana cost of original casted spell
6183 uint32 originalSpellId
= procSpell
->Id
;
6186 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6188 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6190 switch(procSpell
->Id
)
6192 case 25914: originalSpellId
= 20473; break;
6193 case 25913: originalSpellId
= 20929; break;
6194 case 25903: originalSpellId
= 20930; break;
6195 case 27175: originalSpellId
= 27174; break;
6196 case 33074: originalSpellId
= 33072; break;
6198 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6204 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6207 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6211 // percent stored in effect 1 (class scripts) base points
6212 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6214 basepoints0
= originalSpell
->manaCost
*percent
/100;
6215 triggered_spell_id
= 20272;
6224 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6226 switch(auraSpellInfo
->SpellIconID
)
6228 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6231 if(!pVictim
|| !pVictim
->isAlive())
6235 switch(triggeredByAura
->GetSpellProto()->Id
)
6238 triggered_spell_id
= 20268; // Rank 1
6241 triggered_spell_id
= 20352; // Rank 2
6244 triggered_spell_id
= 20353; // Rank 3
6247 triggered_spell_id
= 27165; // Rank 4
6250 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6254 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6255 return true; // no hidden cooldown
6257 //Judgement of Light
6260 if(!pVictim
|| !pVictim
->isAlive())
6263 // overwrite non existing triggered spell call in spell.dbc
6265 switch(triggeredByAura
->GetSpellProto()->Id
)
6268 triggered_spell_id
= 20267; // Rank 1
6271 triggered_spell_id
= 20341; // Rank 2
6274 triggered_spell_id
= 20342; // Rank 3
6277 triggered_spell_id
= 20343; // Rank 4
6280 triggered_spell_id
= 27163; // Rank 5
6283 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6286 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6287 return true; // no hidden cooldown
6291 // custom check for proc spell
6292 switch(auraSpellInfo
->Id
)
6294 // Bonus Healing (item spell)
6297 if(!pVictim
|| !pVictim
->isAlive())
6300 // bonus if health < 50%
6301 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6304 // cast at target positive spell
6309 switch(triggered_spell_id
)
6313 // prevent chain of triggered spell from same triggered spell
6314 if(procSpell
&& procSpell
->Id
==20424)
6320 case SPELLFAMILY_SHAMAN
:
6322 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6324 switch(auraSpellInfo
->SpellIconID
)
6328 switch(auraSpellInfo
->Id
)
6330 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6332 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6333 triggered_spell_id
= 23552;
6337 case 23552: // Lightning Shield - trigger shield damage
6339 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6340 triggered_spell_id
= 27635;
6347 // Mana Surge (Shaman T1 bonus)
6353 basepoints0
= procSpell
->manaCost
* 35/100;
6354 triggered_spell_id
= 23571;
6361 if(GetTypeId()!=TYPEID_PLAYER
)
6364 // damage taken that reduces below 30% health
6365 // does NOT mean you must have been >= 30% before
6366 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6369 triggered_spell_id
= 31616;
6371 // need check cooldown now
6372 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6375 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6377 if(pVictim
&& pVictim
->isAlive())
6378 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6384 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6385 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
[0]==7358)
6392 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
[0]==37)
6394 // overwrite non existing triggered spell call in spell.dbc
6395 switch(triggeredByAura
->GetSpellProto()->Id
)
6398 triggered_spell_id
= 26364; break; // Rank 1
6400 triggered_spell_id
= 26365; break; // Rank 2
6402 triggered_spell_id
= 26366; break; // Rank 3
6404 triggered_spell_id
= 26367; break; // Rank 4
6406 triggered_spell_id
= 26369; break; // Rank 5
6408 triggered_spell_id
= 26370; break; // Rank 6
6410 triggered_spell_id
= 26363; break; // Rank 7
6412 triggered_spell_id
= 26371; break; // Rank 8
6414 triggered_spell_id
= 26372; break; // Rank 9
6416 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6427 // standard non-dummy case
6428 if(!triggered_spell_id
)
6430 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6434 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6438 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6442 // not allow proc extra attack spell at extra attack
6443 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6446 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6450 if(!target
|| target
!=this && !target
->isAlive())
6454 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6456 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6458 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6459 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6464 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, int32 scriptId
, uint32 damage
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6466 if(!pVictim
|| !pVictim
->isAlive())
6469 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6470 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6472 uint32 triggered_spell_id
= 0;
6476 case 836: // Improved Blizzard (Rank 1)
6478 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6480 triggered_spell_id
= 12484;
6483 case 988: // Improved Blizzard (Rank 2)
6485 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6487 triggered_spell_id
= 12485;
6490 case 989: // Improved Blizzard (Rank 3)
6492 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6494 triggered_spell_id
= 12486;
6497 case 4086: // Improved Mend Pet (Rank 1)
6498 case 4087: // Improved Mend Pet (Rank 2)
6500 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6501 if(!roll_chance_i(chance
))
6504 triggered_spell_id
= 24406;
6507 case 4533: // Dreamwalker Raiment 2 pieces bonus
6510 if (!roll_chance_i(50))
6513 switch (pVictim
->getPowerType())
6515 case POWER_MANA
: triggered_spell_id
= 28722; break;
6516 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6517 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6523 case 4537: // Dreamwalker Raiment 6 pieces bonus
6524 triggered_spell_id
= 28750; // Blessing of the Claw
6526 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6527 triggered_spell_id
= 37445; // Mana Surge
6532 if(!triggered_spell_id
)
6535 // standard non-dummy case
6536 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6540 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6544 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6547 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6549 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6550 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6555 void Unit::setPowerType(Powers new_powertype
)
6557 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6559 if(GetTypeId() == TYPEID_PLAYER
)
6561 if(((Player
*)this)->GetGroup())
6562 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6564 else if(((Creature
*)this)->isPet())
6566 Pet
*pet
= ((Pet
*)this);
6567 if(pet
->isControlled())
6569 Unit
*owner
= GetOwner();
6570 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6571 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6575 switch(new_powertype
)
6581 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6582 SetPower( POWER_RAGE
,0);
6585 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6586 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6589 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6590 SetPower( POWER_ENERGY
,0);
6592 case POWER_HAPPINESS
:
6593 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6594 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6599 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6601 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6604 static uint64 guid
= 0; // prevent repeating spam same faction problem
6606 if(GetGUID() != guid
)
6608 if(GetTypeId() == TYPEID_PLAYER
)
6609 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6611 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6618 bool Unit::IsHostileTo(Unit
const* unit
) const
6620 // always non-hostile to self
6624 // always non-hostile to GM in GM mode
6625 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6628 // always hostile to enemy
6629 if(getVictim()==unit
|| unit
->getVictim()==this)
6632 // test pet/charm masters instead pers/charmeds
6633 Unit
const* testerOwner
= GetCharmerOrOwner();
6634 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6636 // always hostile to owner's enemy
6637 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6640 // always hostile to enemy owner
6641 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6644 // always hostile to owner of owner's enemy
6645 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6648 Unit
const* tester
= testerOwner
? testerOwner
: this;
6649 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6651 // always non-hostile to target with common owner, or to owner/pet
6655 // special cases (Duel, etc)
6656 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6658 Player
const* pTester
= (Player
const*)tester
;
6659 Player
const* pTarget
= (Player
const*)target
;
6662 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6666 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6670 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6674 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6678 // Green/Blue (can't attack)
6679 if(pTester
->GetTeam()==pTarget
->GetTeam())
6682 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6683 return pTester
->IsPvP() && pTarget
->IsPvP();
6686 // faction base cases
6687 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6688 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6689 if(!tester_faction
|| !target_faction
)
6692 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6695 // PvC forced reaction and reputation case
6696 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6699 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6700 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6701 return forceItr
->second
<= REP_HOSTILE
;
6703 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6704 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6705 if(raw_target_faction
->reputationListID
>=0)
6706 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6707 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6709 // CvP forced reaction and reputation case
6710 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6713 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6714 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6715 return forceItr
->second
<= REP_HOSTILE
;
6717 // apply reputation state
6718 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6719 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6720 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6723 // common faction based case (CvC,PvC,CvP)
6724 return tester_faction
->IsHostileTo(*target_faction
);
6727 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6729 // always friendly to self
6733 // always friendly to GM in GM mode
6734 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6737 // always non-friendly to enemy
6738 if(getVictim()==unit
|| unit
->getVictim()==this)
6741 // test pet/charm masters instead pers/charmeds
6742 Unit
const* testerOwner
= GetCharmerOrOwner();
6743 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6745 // always non-friendly to owner's enemy
6746 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6749 // always non-friendly to enemy owner
6750 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6753 // always non-friendly to owner of owner's enemy
6754 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6757 Unit
const* tester
= testerOwner
? testerOwner
: this;
6758 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6760 // always friendly to target with common owner, or to owner/pet
6764 // special cases (Duel)
6765 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6767 Player
const* pTester
= (Player
const*)tester
;
6768 Player
const* pTarget
= (Player
const*)target
;
6771 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6775 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6779 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6783 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6787 // Green/Blue (non-attackable)
6788 if(pTester
->GetTeam()==pTarget
->GetTeam())
6791 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6792 return !pTarget
->IsPvP();
6795 // faction base cases
6796 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6797 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6798 if(!tester_faction
|| !target_faction
)
6801 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6804 // PvC forced reaction and reputation case
6805 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6808 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6809 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6810 return forceItr
->second
>= REP_FRIENDLY
;
6812 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6813 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6814 if(raw_target_faction
->reputationListID
>=0)
6815 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6816 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6818 // CvP forced reaction and reputation case
6819 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6822 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6823 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6824 return forceItr
->second
>= REP_FRIENDLY
;
6826 // apply reputation state
6827 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6828 if(raw_tester_faction
->reputationListID
>=0 )
6829 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6832 // common faction based case (CvC,PvC,CvP)
6833 return tester_faction
->IsFriendlyTo(*target_faction
);
6836 bool Unit::IsHostileToPlayers() const
6838 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6842 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6843 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6846 return my_faction
->IsHostileToPlayers();
6849 bool Unit::IsNeutralToAll() const
6851 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6855 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6856 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6859 return my_faction
->IsNeutralToAll();
6862 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6864 if(!victim
|| victim
== this)
6867 // dead units can neither attack nor be attacked
6868 if(!isAlive() || !victim
->isAlive())
6871 // player cannot attack in mount state
6872 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6875 // nobody can attack GM in GM-mode
6876 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6878 if(((Player
*)victim
)->isGameMaster())
6883 if(((Creature
*)victim
)->IsInEvadeMode())
6887 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6888 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6889 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6893 if (m_attacking
== victim
)
6895 // switch to melee attack from ranged/magic
6896 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6898 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6899 SendAttackStart(victim
);
6908 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6911 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6912 m_attacking
= victim
;
6913 m_attacking
->_addAttacker(this);
6915 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6916 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6918 if(GetTypeId()==TYPEID_UNIT
)
6920 WorldPacket
data(SMSG_AI_REACTION
, 12);
6922 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6923 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6925 ((Creature
*)this)->CallAssistence();
6926 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6929 // delay offhand weapon attack to next attack time
6930 if(haveOffhandWeapon())
6931 resetAttackTimer(OFF_ATTACK
);
6934 SendAttackStart(victim
);
6939 bool Unit::AttackStop()
6944 Unit
* victim
= m_attacking
;
6946 m_attacking
->_removeAttacker(this);
6950 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6952 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6954 InterruptSpell(CURRENT_MELEE_SPELL
);
6956 if( GetTypeId()==TYPEID_UNIT
)
6958 // reset call assistance
6959 ((Creature
*)this)->SetNoCallAssistence(false);
6962 SendAttackStop(victim
);
6967 void Unit::CombatStop(bool cast
)
6969 if(cast
& IsNonMeleeSpellCasted(false))
6970 InterruptNonMeleeSpells(false);
6973 RemoveAllAttackers();
6974 if( GetTypeId()==TYPEID_PLAYER
)
6975 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6979 void Unit::CombatStopWithPets(bool cast
)
6982 if(Pet
* pet
= GetPet())
6983 pet
->CombatStop(cast
);
6984 if(Unit
* charm
= GetCharm())
6985 charm
->CombatStop(cast
);
6986 if(GetTypeId()==TYPEID_PLAYER
)
6988 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6989 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6990 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6991 guardian
->CombatStop(cast
);
6995 bool Unit::isAttackingPlayer() const
6997 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
7000 Pet
* pet
= GetPet();
7001 if(pet
&& pet
->isAttackingPlayer())
7004 Unit
* charmed
= GetCharm();
7005 if(charmed
&& charmed
->isAttackingPlayer())
7008 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7012 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7013 if(totem
&& totem
->isAttackingPlayer())
7021 void Unit::RemoveAllAttackers()
7023 while (!m_attackers
.empty())
7025 AttackerSet::iterator iter
= m_attackers
.begin();
7026 if(!(*iter
)->AttackStop())
7028 sLog
.outError("WORLD: Unit has an attacker that isnt attacking it!");
7029 m_attackers
.erase(iter
);
7034 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7038 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7040 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7041 if(GetTypeId() == TYPEID_PLAYER
)
7043 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7044 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7046 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7047 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7048 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7049 if (spellInfo
->CasterAuraState
== flag
)
7050 CastSpell(this, itr
->first
, true, NULL
);
7057 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7059 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7060 Unit::AuraMap
& tAuras
= GetAuras();
7061 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7063 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7064 if (spellProto
->CasterAuraState
== flag
)
7066 // exceptions (applied at state but not removed at state change)
7068 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7083 Unit
*Unit::GetOwner() const
7085 uint64 ownerid
= GetOwnerGUID();
7088 return ObjectAccessor::GetUnit(*this, ownerid
);
7091 Unit
*Unit::GetCharmer() const
7093 if(uint64 charmerid
= GetCharmerGUID())
7094 return ObjectAccessor::GetUnit(*this, charmerid
);
7098 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7100 uint64 guid
= GetCharmerOrOwnerGUID();
7101 if(IS_PLAYER_GUID(guid
))
7102 return ObjectAccessor::GetPlayer(*this, guid
);
7104 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7107 Pet
* Unit::GetPet() const
7109 if(uint64 pet_guid
= GetPetGUID())
7111 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7114 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7115 const_cast<Unit
*>(this)->SetPet(0);
7121 Unit
* Unit::GetCharm() const
7123 if(uint64 charm_guid
= GetCharmGUID())
7125 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7128 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7129 const_cast<Unit
*>(this)->SetCharm(0);
7135 void Unit::SetPet(Pet
* pet
)
7137 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7139 // FIXME: hack, speed must be set only at follow
7141 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7142 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
7145 void Unit::SetCharm(Unit
* charmed
)
7147 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7150 void Unit::UnsummonAllTotems()
7152 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7157 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7158 if (OldTotem
&& OldTotem
->isTotem())
7159 ((Totem
*)OldTotem
)->UnSummon();
7163 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7166 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7167 data
.append(pVictim
->GetPackGUID());
7168 data
.append(GetPackGUID());
7169 data
<< uint32(SpellID
);
7170 data
<< uint32(Damage
);
7171 data
<< uint8(critical
? 1 : 0);
7172 data
<< uint8(0); // unused in client?
7173 SendMessageToSet(&data
, true);
7176 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
, bool critical
)
7178 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7179 data
.append(pVictim
->GetPackGUID());
7180 data
.append(GetPackGUID());
7181 data
<< uint32(SpellID
);
7182 data
<< uint32(powertype
);
7183 data
<< uint32(Damage
);
7184 //data << uint8(critical ? 1 : 0); // removed in 2.4.0
7185 SendMessageToSet(&data
, true);
7188 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7190 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7193 int32 BonusDamage
= 0;
7194 if( GetTypeId()==TYPEID_UNIT
)
7196 // Pets just add their bonus damage to their spell damage
7197 // note that their spell damage is just gain of their own auras
7198 if (((Creature
*)this)->isPet())
7200 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7202 // For totems get damage bonus from owner (statue isn't totem in fact)
7203 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7205 if(Unit
* owner
= GetOwner())
7206 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7211 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7213 // Taken/Done fixed damage bonus auras
7214 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7215 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7217 // Damage over Time spells bonus calculation
7218 float DotFactor
= 1.0f
;
7219 if(damagetype
== DOT
)
7221 int32 DotDuration
= GetSpellDuration(spellProto
);
7225 if(DotDuration
> 30000) DotDuration
= 30000;
7226 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7228 for(int j
= 0; j
< 3; j
++)
7230 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7231 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7232 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7239 if(spellProto
->EffectAmplitude
[x
] != 0)
7240 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7243 DoneAdvertisedBenefit
/= DotTicks
;
7244 TakenAdvertisedBenefit
/= DotTicks
;
7249 // Taken/Done total percent damage auras
7250 float DoneTotalMod
= 1.0f
;
7251 float TakenTotalMod
= 1.0f
;
7254 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7255 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7257 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7258 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7259 // -1 == any item class (not wand then)
7260 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7261 // 0 == any inventory type (not wand then)
7263 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7267 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7268 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7269 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7270 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7271 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7274 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7275 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7276 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7277 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7279 // .. taken pct: scripted (increases damage of * against targets *)
7280 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7281 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7283 switch((*i
)->GetModifier()->m_miscvalue
)
7286 case 4920: case 4919:
7287 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7288 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7292 // .. taken pct: dummy auras
7293 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7294 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7296 switch((*i
)->GetSpellProto()->SpellIconID
)
7300 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7302 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7304 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7305 if (mod
< (*i
)->GetModifier()->m_amount
)
7306 mod
= (*i
)->GetModifier()->m_amount
;
7307 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7312 for(int j
=0;j
<3;j
++)
7314 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7316 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7324 // Distribute Damage over multiple effects, reduce by AoE
7325 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7327 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7328 for(int j
= 0; j
< 3; ++j
)
7330 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7331 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7338 switch(spellProto
->SpellFamilyName
)
7340 case SPELLFAMILY_MAGE
:
7341 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7342 if(spellProto
->Id
==12654)
7347 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7349 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7350 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7351 TakenTotalMod
*= 3.0f
;
7353 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7354 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7356 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7357 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7359 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7360 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7363 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7366 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7370 // Arcane Missiles triggered spell
7371 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7375 // Blizzard triggered spell
7376 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7381 case SPELLFAMILY_WARLOCK
:
7383 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7385 CastingTime
= 2800; // 80% from +shadow damage
7386 DoneTotalMod
= 1.0f
;
7387 TakenTotalMod
= 1.0f
;
7390 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7392 CastingTime
= 3360; // 96% from +shadow damage
7393 DoneTotalMod
= 1.0f
;
7394 TakenTotalMod
= 1.0f
;
7396 // Soul Fire - 115% of Fire Damage
7397 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7401 // Curse of Agony - 120% of Shadow Damage
7402 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7406 // Drain Mana - 0% of Shadow Damage
7407 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7411 // Drain Soul 214.3%
7412 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7417 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7419 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7421 // Unstable Affliction - 180%
7422 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7427 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7432 case SPELLFAMILY_PALADIN
:
7433 // Consecration - 95% of Holy Damage
7434 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7439 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7440 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7442 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7443 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7445 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7446 CastingTime
= uint32(wspeed
*3500*0.102f
);
7448 CastingTime
= uint32(wspeed
*3500*0.098f
);
7450 // Judgement of Righteousness - 73%
7451 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7455 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7456 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7461 // Holy shield - 5% of Holy Damage
7462 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7466 // Blessing of Sanctuary - 0%
7467 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7471 // Seal of Righteousness trigger - already computed for parent spell
7472 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7477 case SPELLFAMILY_SHAMAN
:
7479 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7481 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7482 CastingTime
= 749; // ignore CastingTime and use as modifier
7483 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7484 CastingTime
= 280; // ignore CastingTime and use as modifier
7485 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7486 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7488 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7489 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7490 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7492 case SPELLFAMILY_PRIEST
:
7493 // Mana Burn - 0% of Shadow Damage
7494 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7498 // Mind Flay - 59% of Shadow Damage
7499 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7503 // Holy Fire - 86.71%, DoT - 16.5%
7504 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7506 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7507 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7509 // Shadowguard - 28% per charge
7510 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7514 // Touch of Weakeness - 10%
7515 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7519 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7520 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7525 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7530 case SPELLFAMILY_DRUID
:
7531 // Hurricane triggered spell
7532 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7537 case SPELLFAMILY_WARRIOR
:
7538 case SPELLFAMILY_HUNTER
:
7539 case SPELLFAMILY_ROGUE
:
7546 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7548 // Spellmod SpellDamage
7549 float SpellModSpellDamage
= 100.0f
;
7551 if(Player
* modOwner
= GetSpellModOwner())
7552 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7554 SpellModSpellDamage
/= 100.0f
;
7556 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7557 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7559 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7561 // Add flat bonus from spell damage versus
7562 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7564 // apply spellmod to Done damage
7565 if(Player
* modOwner
= GetSpellModOwner())
7566 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7568 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7570 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7571 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7573 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7576 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7578 int32 DoneAdvertisedBenefit
= 0;
7581 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7582 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7583 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7584 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7585 // -1 == any item class (not wand then)
7586 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7587 // 0 == any inventory type (not wand then)
7588 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7590 if (GetTypeId() == TYPEID_PLAYER
)
7592 // Damage bonus from stats
7593 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7594 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7596 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7598 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7599 uint8 eff
= (*i
)->GetEffIndex();
7601 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7602 Stats usedStat
= STAT_INTELLECT
;
7603 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7604 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7606 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7609 // ... and attack power
7610 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7611 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7612 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7613 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7616 return DoneAdvertisedBenefit
;
7619 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7621 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7623 int32 TakenAdvertisedBenefit
= 0;
7624 // ..done (for creature type by mask) in taken
7625 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7626 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7627 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7628 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7631 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7632 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7633 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7634 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7636 return TakenAdvertisedBenefit
;
7639 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7641 // not criting spell
7642 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7645 float crit_chance
= 0.0f
;
7646 switch(spellProto
->DmgClass
)
7648 case SPELL_DAMAGE_CLASS_NONE
:
7650 case SPELL_DAMAGE_CLASS_MAGIC
:
7652 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7654 // For other schools
7655 else if (GetTypeId() == TYPEID_PLAYER
)
7656 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7659 crit_chance
= m_baseSpellCritChance
;
7660 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7663 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7665 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7666 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7667 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7668 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7669 // Modify by player victim resilience
7670 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7671 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7672 // scripted (increase crit chance ... against ... target by x%
7673 if(pVictim
->isFrozen()) // Shatter
7675 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7676 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7678 switch((*i
)->GetModifier()->m_miscvalue
)
7680 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7681 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7682 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7683 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7684 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7691 case SPELL_DAMAGE_CLASS_MELEE
:
7692 case SPELL_DAMAGE_CLASS_RANGED
:
7696 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7697 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7698 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7706 // only players use intelligence for critical chance computations
7707 if(Player
* modOwner
= GetSpellModOwner())
7708 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7710 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7711 if (roll_chance_f(crit_chance
))
7716 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7718 // Calculate critical bonus
7720 switch(spellProto
->DmgClass
)
7722 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7723 case SPELL_DAMAGE_CLASS_RANGED
:
7724 // TODO: write here full calculation for melee/ranged spells
7725 crit_bonus
= damage
;
7728 crit_bonus
= damage
/ 2; // for spells is 50%
7732 // adds additional damage to crit_bonus (from talents)
7733 if(Player
* modOwner
= GetSpellModOwner())
7734 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7738 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7739 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7743 damage
+= crit_bonus
;
7748 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7750 // For totems get healing bonus from owner (statue isn't totem in fact)
7751 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7752 if(Unit
* owner
= GetOwner())
7753 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7757 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7758 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7759 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7760 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7763 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7764 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7767 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7769 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7770 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7772 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7773 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7775 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7778 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7779 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7781 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7782 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7787 float ActualBenefit
= 0.0f
;
7789 if (AdvertisedBenefit
!= 0)
7791 // Healing over Time spells
7792 float DotFactor
= 1.0f
;
7793 if(damagetype
== DOT
)
7795 int32 DotDuration
= GetSpellDuration(spellProto
);
7799 if(DotDuration
> 30000) DotDuration
= 30000;
7800 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7802 for(int j
= 0; j
< 3; j
++)
7804 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7805 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7806 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7813 if(spellProto
->EffectAmplitude
[x
] != 0)
7814 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7816 AdvertisedBenefit
/= DotTicks
;
7820 // distribute healing to all effects, reduce AoE damage
7821 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7823 // 0% bonus for damage and healing spells for leech spells from healing bonus
7824 for(int j
= 0; j
< 3; ++j
)
7826 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7827 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7835 switch (spellProto
->SpellFamilyName
)
7837 case SPELLFAMILY_SHAMAN
:
7838 // Healing stream from totem (add 6% per tick from hill bonus owner)
7839 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7841 // Earth Shield 30% per charge
7842 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7845 case SPELLFAMILY_DRUID
:
7847 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7849 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7850 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7852 // Tranquility triggered spell
7853 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7856 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7859 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7861 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7862 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7865 case SPELLFAMILY_PRIEST
:
7867 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7870 case SPELLFAMILY_PALADIN
:
7871 // Seal and Judgement of Light
7872 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7875 case SPELLFAMILY_WARRIOR
:
7876 case SPELLFAMILY_ROGUE
:
7877 case SPELLFAMILY_HUNTER
:
7882 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7884 // Spellmod SpellDamage
7885 float SpellModSpellDamage
= 100.0f
;
7887 if(Player
* modOwner
= GetSpellModOwner())
7888 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7890 SpellModSpellDamage
/= 100.0f
;
7892 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7895 // use float as more appropriate for negative values and percent applying
7896 float heal
= healamount
+ ActualBenefit
;
7898 // TODO: check for ALL/SPELLS type
7899 // Healing done percent
7900 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7901 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7902 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7904 // apply spellmod to Done amount
7905 if(Player
* modOwner
= GetSpellModOwner())
7906 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7908 // Healing Wave cast
7909 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7911 // Search for Healing Way on Victim (stack up to 3 time)
7913 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7914 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7915 if((*itr
)->GetId() == 29203)
7916 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7919 heal
= heal
* (100 + pctMod
) / 100;
7922 // Healing taken percent
7923 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7925 heal
*= (100.0f
+ minval
) / 100.0f
;
7927 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7929 heal
*= (100.0f
+ maxval
) / 100.0f
;
7931 if (heal
< 0) heal
= 0;
7933 return uint32(heal
);
7936 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7938 int32 AdvertisedBenefit
= 0;
7940 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7941 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7942 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7943 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7945 // Healing bonus of spirit, intellect and strength
7946 if (GetTypeId() == TYPEID_PLAYER
)
7948 // Healing bonus from stats
7949 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7950 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7952 // stat used dependent from misc value (stat index)
7953 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7954 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7957 // ... and attack power
7958 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7959 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7960 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7961 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7963 return AdvertisedBenefit
;
7966 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7968 int32 AdvertisedBenefit
= 0;
7969 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7970 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7971 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7972 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7973 return AdvertisedBenefit
;
7976 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7978 // no charges dependent checks
7979 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7980 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7981 if(itr
->type
& shoolMask
)
7984 // charges dependent checks
7985 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7986 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7988 if(itr
->type
& shoolMask
)
7992 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7993 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
7995 if((*auraItr
)->GetId()==itr
->spellId
)
7997 if((*auraItr
)->m_procCharges
> 0)
7999 --(*auraItr
)->m_procCharges
;
8000 if((*auraItr
)->m_procCharges
==0)
8001 RemoveAurasDueToSpell(itr
->spellId
);
8014 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8021 //FIX ME this hack: don't get feared if stunned
8022 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8024 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8028 // not have spells with charges currently
8029 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8030 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8031 if(itr
->type
== spellInfo
->Dispel
)
8034 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8036 // not have spells with charges currently
8037 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8038 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8039 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8040 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8044 // charges dependent checks
8046 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8047 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8049 if(itr
->type
== spellInfo
->Mechanic
)
8053 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8054 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8056 if((*auraItr
)->GetId()==itr
->spellId
)
8058 if((*auraItr
)->m_procCharges
> 0)
8060 --(*auraItr
)->m_procCharges
;
8061 if((*auraItr
)->m_procCharges
==0)
8062 RemoveAurasDueToSpell(itr
->spellId
);
8075 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8077 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8078 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8079 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8080 if(itr
->type
== effect
)
8083 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8084 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8085 if(itr
->type
== mechanic
)
8091 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8096 uint32 family
= spellInfo
->SpellFamilyName
;
8097 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8099 if((family
== 5 && flags
== 256) || //Searing Pain
8100 (family
== 6 && flags
== 8192) || //Mind Blast
8101 (family
== 11 && flags
== 1048576)) //Earth Shock
8107 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8115 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8117 // Taken/Done fixed damage bonus auras
8118 int32 DoneFlatBenefit
= 0;
8119 int32 TakenFlatBenefit
= 0;
8121 // ..done (for creature type by mask) in taken
8122 AuraList
const& mDamageDoneCreature
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8123 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8124 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8125 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8128 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8130 // ..done (base at attack power for marked target and base at attack power for creature type)
8132 if(attType
== RANGED_ATTACK
)
8134 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8136 // ..done (base at attack power and creature type)
8137 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8138 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8139 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8140 APbonus
+= (*i
)->GetModifier()->m_amount
;
8144 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8146 // ..done (base at attack power and creature type)
8147 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8148 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8149 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8150 APbonus
+= (*i
)->GetModifier()->m_amount
;
8153 if (APbonus
!=0) // Can be negative
8155 bool normalized
= false;
8158 for (uint8 i
= 0; i
<3;i
++)
8160 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8168 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8172 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8173 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8174 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8175 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8177 if(attType
!=RANGED_ATTACK
)
8178 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8180 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8182 // Done/Taken total percent damage auras
8183 float DoneTotalMod
= 1;
8184 float TakenTotalMod
= 1;
8187 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8188 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8190 AuraList
const& mDamageDoneVersus
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8191 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8192 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8193 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8196 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8197 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8198 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8199 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8201 // .. taken pct: dummy auras
8202 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8203 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8205 switch((*i
)->GetSpellProto()->SpellIconID
)
8209 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8211 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8213 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8214 if (mod
< (*i
)->GetModifier()->m_amount
)
8215 mod
= (*i
)->GetModifier()->m_amount
;
8216 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8221 if(spellProto
==NULL
)
8223 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8224 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8225 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8230 // .. taken pct: class scripts
8231 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8232 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8234 switch((*i
)->GetMiscValue())
8236 case 6427: case 6428: // Dirty Deeds
8237 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8239 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8240 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8242 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8246 // effect 0 have expected value but in negative state
8247 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8253 if(attType
!= RANGED_ATTACK
)
8255 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8256 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8257 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8261 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8262 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8263 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8266 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8268 // apply spellmod to Done damage
8271 if(Player
* modOwner
= GetSpellModOwner())
8272 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8275 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8277 // bonus result can be negative
8278 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8281 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8285 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8288 if(itr
->type
== type
)
8290 m_spellImmune
[op
].erase(itr
);
8291 next
= m_spellImmune
[op
].begin();
8295 Immune
.spellId
= spellId
;
8297 m_spellImmune
[op
].push_back(Immune
);
8301 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8303 if(itr
->spellId
== spellId
)
8305 m_spellImmune
[op
].erase(itr
);
8313 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8315 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8317 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8318 RemoveAurasWithDispelType(type
);
8321 float Unit::GetWeaponProcChance() const
8323 // normalized proc chance for weapon attack speed
8324 // (odd formulae...)
8325 if(isAttackReady(BASE_ATTACK
))
8326 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8327 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8328 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8332 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8334 // proc per minute chance calculation
8335 if (PPM
<= 0) return 0.0f
;
8336 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8340 void Unit::Mount(uint32 mount
)
8345 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8347 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8349 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8352 if(GetTypeId() == TYPEID_PLAYER
)
8354 Pet
* pet
= GetPet();
8357 if(pet
->isControlled())
8359 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8360 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8363 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8366 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8370 void Unit::Unmount()
8375 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8377 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8378 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8380 // only resummon old pet if the player is already added to a map
8381 // this prevents adding a pet to a not created map which would otherwise cause a crash
8382 // (it could probably happen when logging in after a previous crash)
8383 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8385 Pet
* NewPet
= new Pet
;
8386 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8389 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8393 void Unit::SetInCombatWith(Unit
* enemy
)
8395 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8398 SetInCombatState(true);
8403 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8405 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8406 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8408 SetInCombatState(true);
8412 SetInCombatState(false);
8415 void Unit::SetInCombatState(bool PvP
)
8417 // only alive units can be in combat
8422 m_CombatTimer
= 5000;
8423 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8425 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8426 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8429 void Unit::ClearInCombat()
8432 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8434 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8435 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8437 // Player's state will be cleared in Player::UpdateContestedPvP
8438 if(GetTypeId()!=TYPEID_PLAYER
)
8439 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8442 bool Unit::isTargetableForAttack() const
8444 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8447 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8450 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8453 int32
Unit::ModifyHealth(int32 dVal
)
8460 int32 curHealth
= (int32
)GetHealth();
8462 int32 val
= dVal
+ curHealth
;
8469 int32 maxHealth
= (int32
)GetMaxHealth();
8474 gain
= val
- curHealth
;
8476 else if(curHealth
!= maxHealth
)
8478 SetHealth(maxHealth
);
8479 gain
= maxHealth
- curHealth
;
8485 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8492 int32 curPower
= (int32
)GetPower(power
);
8494 int32 val
= dVal
+ curPower
;
8501 int32 maxPower
= (int32
)GetMaxPower(power
);
8505 SetPower(power
,val
);
8506 gain
= val
- curPower
;
8508 else if(curPower
!= maxPower
)
8510 SetPower(power
,maxPower
);
8511 gain
= maxPower
- curPower
;
8517 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8522 // Always can see self
8526 // player visible for other player if not logout and at same transport
8527 // including case when player is out of world
8528 bool at_same_transport
=
8529 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8530 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8531 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8532 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8535 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8538 // forbidden to seen (at GM respawn command)
8539 if(m_Visibility
==VISIBILITY_RESPAWN
)
8542 // always seen by owner
8543 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8546 // Grid dead/alive checks
8547 if( u
->GetTypeId()==TYPEID_PLAYER
)
8549 // non visible at grid for any stealth state
8550 if(!IsVisibleInGridForPlayer((Player
*)u
))
8553 // if player is dead then he can't detect anyone in anycases
8559 // all dead creatures/players not visible for any creatures
8560 if(!u
->isAlive() || !isAlive())
8564 // different visible distance checks
8565 if(u
->isInFlight()) // what see player in flight
8567 // use object grey distance for all (only see objects any way)
8568 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8571 else if(!isAlive()) // distance for show body
8573 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8576 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8578 if(u
->GetTypeId()==TYPEID_PLAYER
)
8580 // Players far than max visible distance for player or not in our map are not visible too
8581 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8586 // Units far than max visible distance for creature or not in our map are not visible too
8587 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8591 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8593 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8594 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8597 else // distance for show creature
8599 // Units far than max visible distance for creature or not in our map are not visible too
8600 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8604 // Visible units, always are visible for all units, except for units under invisibility
8605 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8608 // GMs see any players, not higher GMs and all units
8609 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8611 if(GetTypeId() == TYPEID_PLAYER
)
8612 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8617 // non faction visibility non-breakable for non-GMs
8618 if (m_Visibility
== VISIBILITY_OFF
)
8622 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8624 // detectable invisibility case
8626 // Invisible units, always are visible for units under same invisibility type
8627 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8628 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8629 u
->canDetectInvisibilityOf(this) ||
8630 // Units that can detect invisibility always are visible for units that can be detected
8631 canDetectInvisibilityOf(u
) ))
8636 // special cases for always overwrite invisibility/stealth
8637 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8640 if (!u
->IsHostileTo(this))
8642 // 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)
8643 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8645 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8648 // else apply same rules as for hostile case (detecting check for stealth)
8654 // Hunter mark functionality
8655 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8656 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8657 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8660 // else apply detecting check for stealth
8663 // none other cases for detect invisibility, so invisible
8667 // else apply stealth detecting check
8670 // unit got in stealth in this moment and must ignore old detected state
8671 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8674 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8675 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8678 // NOW ONLY STEALTH CASE
8680 // stealth and detected and visible for some seconds
8681 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8684 //if in non-detect mode then invisible for unit
8690 // If is attacked then stealth is lost, some creature can use stealth too
8691 if( !getAttackers().empty() )
8694 // If there is collision rogue is seen regardless of level difference
8695 // TODO: check sizes in DB
8696 float distance
= GetDistance(u
);
8697 if (distance
< 0.24f
)
8700 //If a mob or player is stunned he will not be able to detect stealth
8701 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8704 // Creature can detect target only in aggro radius
8705 if(u
->GetTypeId() != TYPEID_PLAYER
)
8707 //Always invisible from back and out of aggro range
8708 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8714 //Always invisible from back
8715 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8720 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8721 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8723 //Calculation if target is in front
8725 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8726 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8728 //Visible distance is modified by
8729 //-Level Diff (every level diff = 1.0f in visible distance)
8730 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(this->getLevelForTarget(u
));
8732 //This allows to check talent tree and will add addition stealth dependent on used points)
8733 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8737 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8738 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8739 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8741 if(distance
> visibleDistance
)
8745 // Now check is target visible with LoS
8747 u
->GetPosition(ox
,oy
,oz
);
8748 return IsWithinLOS(ox
,oy
,oz
);
8751 void Unit::SetVisibility(UnitVisibility x
)
8757 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8759 if(GetTypeId()==TYPEID_PLAYER
)
8760 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8762 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8766 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8768 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8770 for(uint32 i
= 0; i
< 10; ++i
)
8772 if(((1 << i
) & mask
)==0)
8775 // find invisibility level
8776 uint32 invLevel
= 0;
8777 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8778 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8779 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8780 invLevel
= (*itr
)->GetModifier()->m_amount
;
8782 // find invisibility detect level
8783 uint32 detectLevel
= 0;
8784 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8785 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8786 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8787 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8789 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8791 detectLevel
= ((Player
*)this)->GetDrunkValue();
8794 if(invLevel
<= detectLevel
)
8802 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8804 int32 main_speed_mod
= 0;
8805 float stack_bonus
= 1.0f
;
8806 float non_stack_bonus
= 1.0f
;
8814 if (IsMounted()) // Use on mount auras
8816 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8817 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8818 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8822 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8823 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8824 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8832 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8839 if (IsMounted()) // Use on mount auras
8840 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8841 else // Use not mount (shapeshift for example) auras (should stack)
8842 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8843 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8844 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8850 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8854 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8855 // now we ready for speed calculation
8856 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8864 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8865 // TODO: possible affect only on MOVE_RUN
8866 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8868 // Use speed from aura
8869 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8870 if (speed
> max_speed
)
8879 // Apply strongest slow aura mod to speed
8880 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8882 speed
*=(100.0f
+ slow
)/100.0f
;
8883 SetSpeed(mtype
, speed
, forced
);
8886 float Unit::GetSpeed( UnitMoveType mtype
) const
8888 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8891 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8896 // Update speed only on change
8897 if (m_speed_rate
[mtype
] == rate
)
8900 m_speed_rate
[mtype
] = rate
;
8902 propagateSpeedChange();
8904 // Send speed change packet only for player
8905 if (GetTypeId()!=TYPEID_PLAYER
)
8914 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8917 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8920 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8923 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8926 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8929 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8932 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8935 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8938 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8942 data
.append(GetPackGUID());
8943 data
<< uint32(0); //movement flags
8944 data
<< uint16(0); //unk
8945 data
<< uint32(getMSTime());
8946 data
<< float(GetPositionX());
8947 data
<< float(GetPositionY());
8948 data
<< float(GetPositionZ());
8949 data
<< float(GetOrientation());
8950 data
<< uint32(0); //flag unk
8951 data
<< float(GetSpeed(mtype
));
8952 SendMessageToSet( &data
, true );
8956 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8957 // and do it only for real sent packets and use run for run/mounted as client expected
8958 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8962 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8965 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8968 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8971 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8974 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8977 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8980 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8983 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8986 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8989 data
.append(GetPackGUID());
8991 if (mtype
== MOVE_RUN
)
8992 data
<< uint8(0); // new 2.1.0
8993 data
<< float(GetSpeed(mtype
));
8994 SendMessageToSet( &data
, true );
8996 if(Pet
* pet
= GetPet())
8997 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9000 void Unit::SetHover(bool on
)
9003 CastSpell(this,11010,true);
9005 RemoveAurasDueToSpell(11010);
9008 void Unit::setDeathState(DeathState s
)
9010 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9014 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9016 if(IsNonMeleeSpellCasted(false))
9017 InterruptNonMeleeSpells(false);
9022 RemoveAllAurasOnDeath();
9023 UnsummonAllTotems();
9025 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9026 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9027 // remove aurastates allowing special moves
9028 ClearAllReactives();
9029 ClearDiminishings();
9031 else if(s
== JUST_ALIVED
)
9033 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9036 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9038 //_ApplyAllAuraMods();
9043 /*########################################
9045 ######## AGGRO SYSTEM ########
9047 ########################################*/
9048 bool Unit::CanHaveThreatList() const
9050 // only creatures can have threat list
9051 if( GetTypeId() != TYPEID_UNIT
)
9054 // only alive units can have threat list
9058 // pets and totems can not have threat list
9059 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() )
9065 //======================================================================
9067 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9069 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9072 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9074 return threat
* m_threatModifier
[school
];
9077 //======================================================================
9079 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9081 // Only mobs can manage threat lists
9082 if(CanHaveThreatList())
9083 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9086 //======================================================================
9088 void Unit::DeleteThreatList()
9090 m_ThreatManager
.clearReferences();
9093 //======================================================================
9095 void Unit::TauntApply(Unit
* taunter
)
9097 assert(GetTypeId()== TYPEID_UNIT
);
9099 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9102 if(!CanHaveThreatList())
9105 Unit
*target
= getVictim();
9106 if(target
&& target
== taunter
)
9109 SetInFront(taunter
);
9110 if (((Creature
*)this)->AI())
9111 ((Creature
*)this)->AI()->AttackStart(taunter
);
9113 m_ThreatManager
.tauntApply(taunter
);
9116 //======================================================================
9118 void Unit::TauntFadeOut(Unit
*taunter
)
9120 assert(GetTypeId()== TYPEID_UNIT
);
9122 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9125 if(!CanHaveThreatList())
9128 Unit
*target
= getVictim();
9129 if(!target
|| target
!= taunter
)
9132 if(m_ThreatManager
.isThreatListEmpty())
9134 if(((Creature
*)this)->AI())
9135 ((Creature
*)this)->AI()->EnterEvadeMode();
9139 m_ThreatManager
.tauntFadeOut(taunter
);
9140 target
= m_ThreatManager
.getHostilTarget();
9142 if (target
&& target
!= taunter
)
9145 if (((Creature
*)this)->AI())
9146 ((Creature
*)this)->AI()->AttackStart(target
);
9150 //======================================================================
9152 bool Unit::SelectHostilTarget()
9154 //function provides main threat functionality
9155 //next-victim-selection algorithm and evade mode are called
9156 //threat list sorting etc.
9158 assert(GetTypeId()== TYPEID_UNIT
);
9159 Unit
* target
= NULL
;
9161 //This function only useful once AI has been initilazied
9162 if (!((Creature
*)this)->AI())
9165 if(!m_ThreatManager
.isThreatListEmpty())
9167 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9169 target
= m_ThreatManager
.getHostilTarget();
9175 if(!hasUnitState(UNIT_STAT_STUNNED
))
9177 ((Creature
*)this)->AI()->AttackStart(target
);
9181 // no target but something prevent go to evade mode
9182 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9185 // last case when creature don't must go to evade mode:
9186 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9187 // for example at owner command to pet attack some far away creature
9188 // Note: creature not have targeted movement generator but have attacker in this case
9189 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9191 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9193 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9198 // enter in evade mode in other case
9199 ((Creature
*)this)->AI()->EnterEvadeMode();
9204 //======================================================================
9205 //======================================================================
9206 //======================================================================
9208 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9210 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9212 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9214 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9215 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9216 level
= spellProto
->maxLevel
;
9218 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9219 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9220 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9221 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9222 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9224 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9225 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9226 int32 value
= basePoints
+ randvalue
;
9228 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9229 value
+= (int32
)(comboDamage
* comboPoints
);
9231 if(Player
* modOwner
= GetSpellModOwner())
9233 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9234 switch(effect_index
)
9237 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9240 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9243 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9248 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9249 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9250 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9251 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9256 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9258 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9260 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9262 int32 minduration
= GetSpellDuration(spellProto
);
9263 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9267 if( minduration
!= -1 && minduration
!= maxduration
)
9268 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9270 duration
= minduration
;
9274 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9275 // Find total mod value (negative bonus)
9276 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9277 // Find max mod (negative bonus)
9278 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9280 int32 durationMod
= 0;
9281 // Select strongest negative mod
9282 if (durationMod_always
> durationMod_not_stack
)
9283 durationMod
= durationMod_not_stack
;
9285 durationMod
= durationMod_always
;
9287 if (durationMod
!= 0)
9288 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9290 if (duration
< 0) duration
= 0;
9296 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9298 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9300 if(i
->DRGroup
!= group
)
9304 return DIMINISHING_LEVEL_1
;
9307 return DIMINISHING_LEVEL_1
;
9309 // If last spell was casted more than 15 seconds ago - reset the count.
9310 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9312 i
->hitCount
= DIMINISHING_LEVEL_1
;
9313 return DIMINISHING_LEVEL_1
;
9315 // or else increase the count.
9318 return DiminishingLevels(i
->hitCount
);
9321 return DIMINISHING_LEVEL_1
;
9324 void Unit::IncrDiminishing(DiminishingGroup group
)
9326 // Checking for existing in the table
9327 bool IsExist
= false;
9328 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9330 if(i
->DRGroup
!= group
)
9334 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9341 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9344 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9346 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9349 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9350 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9352 // test pet/charm masters instead pets/charmeds
9353 Unit
const* targetOwner
= GetCharmerOrOwner();
9354 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9356 Unit
const* target
= targetOwner
? targetOwner
: this;
9357 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9359 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9365 // Some diminishings applies to mobs too (for example, Stun)
9366 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9368 DiminishingLevels diminish
= Level
;
9371 case DIMINISHING_LEVEL_1
: break;
9372 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9373 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9374 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9379 duration
= int32(duration
* mod
);
9382 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9384 // Checking for existing in the table
9385 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9387 if(i
->DRGroup
!= group
)
9390 i
->hitTime
= getMSTime();
9401 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9403 return ObjectAccessor::GetUnit(object
,guid
);
9406 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9408 return isVisibleForOrDetect(u
,false,inVisibleList
);
9411 uint32
Unit::GetCreatureType() const
9413 if(GetTypeId() == TYPEID_PLAYER
)
9415 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9416 if(ssEntry
&& ssEntry
->creatureType
> 0)
9417 return ssEntry
->creatureType
;
9419 return CREATURE_TYPE_HUMANOID
;
9422 return ((Creature
*)this)->GetCreatureInfo()->type
;
9425 /*#######################################
9427 ######## STAT SYSTEM ########
9429 #######################################*/
9431 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9433 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9435 sLog
.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
9441 switch(modifierType
)
9445 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9449 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9452 val
= (100.0f
+ amount
) / 100.0f
;
9453 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9460 if(!CanModifyStats())
9465 case UNIT_MOD_STAT_STRENGTH
:
9466 case UNIT_MOD_STAT_AGILITY
:
9467 case UNIT_MOD_STAT_STAMINA
:
9468 case UNIT_MOD_STAT_INTELLECT
:
9469 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9471 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9472 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9476 case UNIT_MOD_FOCUS
:
9477 case UNIT_MOD_ENERGY
:
9478 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9480 case UNIT_MOD_RESISTANCE_HOLY
:
9481 case UNIT_MOD_RESISTANCE_FIRE
:
9482 case UNIT_MOD_RESISTANCE_NATURE
:
9483 case UNIT_MOD_RESISTANCE_FROST
:
9484 case UNIT_MOD_RESISTANCE_SHADOW
:
9485 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9487 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9488 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9490 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9491 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9492 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9501 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9503 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9505 sLog
.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
9509 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9512 return m_auraModifiersGroup
[unitMod
][modifierType
];
9515 float Unit::GetTotalStatValue(Stats stat
) const
9517 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9519 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9522 // value = ((base_value * base_pct) + total_value) * total_pct
9523 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9524 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9525 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9526 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9531 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9533 if(unitMod
>= UNIT_MOD_END
)
9535 sLog
.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
9539 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9542 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9543 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9544 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9545 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9550 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9552 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9556 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9557 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9558 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9559 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9560 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9561 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9570 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9572 Stats stat
= STAT_STRENGTH
;
9576 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9577 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9578 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9579 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9580 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9589 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9591 Powers power
= POWER_MANA
;
9595 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9596 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9597 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9598 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9599 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9608 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9610 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9612 float val
= GetTotalAuraModValue(unitMod
);
9619 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9621 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9624 return m_weaponDamage
[attType
][type
];
9627 void Unit::SetLevel(uint32 lvl
)
9629 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9632 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9633 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9636 void Unit::SetHealth(uint32 val
)
9638 uint32 maxHealth
= GetMaxHealth();
9642 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9645 if(GetTypeId() == TYPEID_PLAYER
)
9647 if(((Player
*)this)->GetGroup())
9648 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9650 else if(((Creature
*)this)->isPet())
9652 Pet
*pet
= ((Pet
*)this);
9653 if(pet
->isControlled())
9655 Unit
*owner
= GetOwner();
9656 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9657 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9662 void Unit::SetMaxHealth(uint32 val
)
9664 uint32 health
= GetHealth();
9665 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9668 if(GetTypeId() == TYPEID_PLAYER
)
9670 if(((Player
*)this)->GetGroup())
9671 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9673 else if(((Creature
*)this)->isPet())
9675 Pet
*pet
= ((Pet
*)this);
9676 if(pet
->isControlled())
9678 Unit
*owner
= GetOwner();
9679 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9680 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9688 void Unit::SetPower(Powers power
, uint32 val
)
9690 uint32 maxPower
= GetMaxPower(power
);
9694 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9696 WorldPacket
data(SMSG_POWER_UPDATE
);
9697 data
.append(GetPackGUID());
9698 data
<< uint8(power
);
9699 data
<< uint32(val
);
9700 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9703 if(GetTypeId() == TYPEID_PLAYER
)
9705 if(((Player
*)this)->GetGroup())
9706 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9708 else if(((Creature
*)this)->isPet())
9710 Pet
*pet
= ((Pet
*)this);
9711 if(pet
->isControlled())
9713 Unit
*owner
= GetOwner();
9714 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9715 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9718 // Update the pet's character sheet with happiness damage bonus
9719 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9721 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9726 void Unit::SetMaxPower(Powers power
, uint32 val
)
9728 uint32 cur_power
= GetPower(power
);
9729 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9732 if(GetTypeId() == TYPEID_PLAYER
)
9734 if(((Player
*)this)->GetGroup())
9735 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9737 else if(((Creature
*)this)->isPet())
9739 Pet
*pet
= ((Pet
*)this);
9740 if(pet
->isControlled())
9742 Unit
*owner
= GetOwner();
9743 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9744 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9749 SetPower(power
, val
);
9752 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9754 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9757 if(GetTypeId() == TYPEID_PLAYER
)
9759 if(((Player
*)this)->GetGroup())
9760 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9762 else if(((Creature
*)this)->isPet())
9764 Pet
*pet
= ((Pet
*)this);
9765 if(pet
->isControlled())
9767 Unit
*owner
= GetOwner();
9768 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9769 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9774 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9776 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9779 if(GetTypeId() == TYPEID_PLAYER
)
9781 if(((Player
*)this)->GetGroup())
9782 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9784 else if(((Creature
*)this)->isPet())
9786 Pet
*pet
= ((Pet
*)this);
9787 if(pet
->isControlled())
9789 Unit
*owner
= GetOwner();
9790 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9791 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9796 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9798 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9800 tAuraProcTriggerDamage
.push_back(aura
);
9802 tAuraProcTriggerDamage
.remove(aura
);
9805 uint32
Unit::GetCreatePowers( Powers power
) const
9807 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9810 case POWER_MANA
: return GetCreateMana();
9811 case POWER_RAGE
: return 1000;
9812 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9813 case POWER_ENERGY
: return 100;
9814 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9815 case POWER_RUNIC_POWER
: return 1000;
9821 void Unit::AddToWorld()
9823 Object::AddToWorld();
9826 void Unit::RemoveFromWorld()
9831 RemoveNotOwnSingleTargetAuras();
9834 Object::RemoveFromWorld();
9837 void Unit::CleanupsBeforeDelete()
9839 if(m_uint32Values
) // only for fully created object
9841 InterruptNonMeleeSpells(true);
9842 m_Events
.KillAllEvents();
9844 ClearComboPointHolders();
9846 getHostilRefManager().setOnlineOfflineState(false);
9848 RemoveAllGameObjects();
9849 RemoveAllDynObjects();
9850 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9855 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9858 m_charmInfo
= new CharmInfo(charm
);
9862 CharmInfo::CharmInfo(Unit
* unit
)
9863 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9865 for(int i
=0; i
<4; ++i
)
9867 m_charmspells
[i
].spellId
= 0;
9868 m_charmspells
[i
].active
= ACT_DISABLED
;
9872 void CharmInfo::InitPetActionBar()
9874 // the first 3 SpellOrActions are attack, follow and stay
9875 for(uint32 i
= 0; i
< 3; i
++)
9877 PetActionBar
[i
].Type
= ACT_COMMAND
;
9878 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9880 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9881 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9883 for(uint32 i
=0; i
< 4; i
++)
9885 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9886 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9890 void CharmInfo::InitEmptyActionBar()
9892 for(uint32 x
= 1; x
< 10; ++x
)
9894 PetActionBar
[x
].Type
= ACT_CAST
;
9895 PetActionBar
[x
].SpellOrAction
= 0;
9897 PetActionBar
[0].Type
= ACT_COMMAND
;
9898 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9901 void CharmInfo::InitPossessCreateSpells()
9903 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9906 InitEmptyActionBar(); //charm action bar
9908 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9910 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9911 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9913 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9917 void CharmInfo::InitCharmCreateSpells()
9919 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9921 InitEmptyActionBar();
9927 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9929 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9930 m_charmspells
[x
].spellId
= spellId
;
9935 if (IsPassiveSpell(spellId
))
9937 m_unit
->CastSpell(m_unit
, spellId
, true);
9938 m_charmspells
[x
].active
= ACT_PASSIVE
;
9942 ActiveStates newstate
;
9943 bool onlyselfcast
= true;
9944 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9946 if(!spellInfo
) onlyselfcast
= false;
9947 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9949 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9950 onlyselfcast
= false;
9953 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9954 newstate
= ACT_DISABLED
;
9956 newstate
= ACT_CAST
;
9958 AddSpellToAB(0, spellId
, newstate
);
9963 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9965 for(uint8 i
= 0; i
< 10; i
++)
9967 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9969 PetActionBar
[i
].SpellOrAction
= newid
;
9972 if(newstate
== ACT_DECIDE
)
9973 PetActionBar
[i
].Type
= ACT_DISABLED
;
9975 PetActionBar
[i
].Type
= newstate
;
9984 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9986 if(IsPassiveSpell(spellid
))
9989 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9991 if(spellid
== m_charmspells
[x
].spellId
)
9993 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
9998 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10000 m_petnumber
= petnumber
;
10002 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10004 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10007 bool Unit::isFrozen() const
10009 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10010 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10011 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10016 struct ProcTriggeredData
10018 ProcTriggeredData(SpellEntry
const * _spellInfo
, uint32 _spellParam
, Aura
* _triggeredByAura
, uint32 _cooldown
)
10019 : spellInfo(_spellInfo
), spellParam(_spellParam
), triggeredByAura(_triggeredByAura
),
10020 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10021 cooldown(_cooldown
)
10024 SpellEntry
const * spellInfo
;
10026 Aura
* triggeredByAura
;
10027 Unit::spellEffectPair triggeredByAura_SpellPair
;
10031 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10033 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10035 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10037 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10038 ProcTriggeredList procTriggered
;
10040 AuraList
const& auras
= GetAurasByType(*aur
);
10041 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10045 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
10049 SpellProcEventEntry
const *spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10050 if(!spellProcEvent
)
10052 // used to prevent spam in log about same non-handled spells
10053 static std::set
<uint32
> nonHandledSpellProcSet
;
10055 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10057 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10058 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10061 // spell.dbc use totally different flags, that only can create problems if used.
10065 // Check spellProcEvent data requirements
10066 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10069 // Check if current equipment allows aura to proc
10070 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10072 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10074 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10076 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10079 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10081 // Check if player is wearing shield
10082 Item
*item
= ((Player
*)this)->GetShield(true);
10083 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10088 float chance
= (float)spellProto
->procChance
;
10090 if(Player
* modOwner
= GetSpellModOwner())
10091 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10093 if(!isVictim
&& spellProcEvent
->ppmRate
!= 0)
10095 uint32 WeaponSpeed
= GetAttackTime(attType
);
10096 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10099 if(roll_chance_f(chance
))
10101 uint32 cooldown
= spellProcEvent
->cooldown
;
10103 uint32 i_spell_eff
= (*i
)->GetEffIndex();
10105 int32 i_spell_param
;
10108 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10109 i_spell_param
= procFlag
;
10111 case SPELL_AURA_DUMMY
:
10112 case SPELL_AURA_PRAYER_OF_MENDING
:
10113 case SPELL_AURA_MOD_HASTE
:
10114 i_spell_param
= i_spell_eff
;
10116 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10117 i_spell_param
= (*i
)->GetModifier()->m_miscvalue
;
10120 i_spell_param
= (*i
)->GetModifier()->m_amount
;
10124 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
, cooldown
) );
10128 // Handle effects proceed this time
10129 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10131 // Some auras can be deleted in function called in this loop (except first, ofc)
10132 // Until storing auras in std::multimap to hard check deleting by another way
10133 if(i
!= procTriggered
.begin())
10135 bool found
= false;
10136 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10137 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10138 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10140 if(itr
->second
==i
->triggeredByAura
)
10149 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
);
10150 sLog
.outError("It can be deleted one from early proccesed auras:");
10151 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10152 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10153 sLog
.outError(" <end of list>");
10158 // save charges existence before processing to prevent crash at access to deleted triggered aura after
10159 bool triggeredByAuraWithCharges
= i
->triggeredByAura
->m_procCharges
> 0;
10161 bool casted
= false;
10164 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10166 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10167 casted
= HandleProcTriggerSpell(pTarget
, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
,attType
,i
->cooldown
);
10170 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10172 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i
->spellParam
, i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10173 uint32 damage
= i
->spellParam
;
10174 SpellNonMeleeDamageLog(pTarget
, i
->spellInfo
->Id
, damage
, true, true);
10178 case SPELL_AURA_DUMMY
:
10180 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10181 casted
= HandleDummyAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10184 case SPELL_AURA_PRAYER_OF_MENDING
:
10186 sLog
.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10188 // aura can be deleted at casts
10189 int32 heal
= i
->triggeredByAura
->GetModifier()->m_amount
;
10190 uint64 caster_guid
= i
->triggeredByAura
->GetCasterGUID();
10193 int32 jumps
= i
->triggeredByAura
->m_procCharges
-1;
10195 // current aura expire
10196 i
->triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10198 // next target selection
10199 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10201 Aura
* aura
= i
->triggeredByAura
;
10203 SpellEntry
const* spellProto
= aura
->GetSpellProto();
10204 uint32 effIdx
= aura
->GetEffIndex();
10207 if (spellProto
->EffectRadiusIndex
[effIdx
])
10208 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10210 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10212 if(Player
* caster
= ((Player
*)aura
->GetCaster()))
10214 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10216 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10218 // aura will applied from caster, but spell casted from current aura holder
10219 SpellModifier
*mod
= new SpellModifier
;
10220 mod
->op
= SPELLMOD_CHARGES
;
10221 mod
->value
= jumps
-5; // negative
10222 mod
->type
= SPELLMOD_FLAT
;
10223 mod
->spellId
= spellProto
->Id
;
10224 mod
->effectId
= effIdx
;
10225 mod
->lastAffected
= NULL
;
10226 mod
->mask
= spellProto
->SpellFamilyFlags
;
10229 caster
->AddSpellMod(mod
, true);
10230 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,aura
,caster
->GetGUID());
10231 caster
->AddSpellMod(mod
, false);
10237 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10241 case SPELL_AURA_MOD_HASTE
:
10243 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10244 casted
= HandleHasteAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10247 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10249 // nothing do, just charges counter
10250 // but count only in case appropriate school damage
10251 casted
= i
->triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10254 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10256 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10257 casted
= HandleOverrideClassScriptAuraProc(pTarget
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
,i
->cooldown
);
10262 // nothing do, just charges counter
10268 // Update charge (aura can be removed by triggers)
10269 if(casted
&& triggeredByAuraWithCharges
)
10271 // need found aura (can be dropped by triggers)
10272 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10273 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10274 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10276 if(itr
->second
== i
->triggeredByAura
)
10278 if(i
->triggeredByAura
->m_procCharges
> 0)
10279 i
->triggeredByAura
->m_procCharges
-= 1;
10281 i
->triggeredByAura
->UpdateAuraCharges();
10288 // Safely remove auras with zero charges
10289 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10292 if((*i
)->m_procCharges
== 0)
10294 RemoveAurasDueToSpell((*i
)->GetId());
10295 next
= auras
.begin();
10301 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10303 return SPELL_SCHOOL_MASK_NORMAL
;
10306 Player
* Unit::GetSpellModOwner()
10308 if(GetTypeId()==TYPEID_PLAYER
)
10309 return (Player
*)this;
10310 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10312 Unit
* owner
= GetOwner();
10313 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10314 return (Player
*)owner
;
10319 ///----------Pet responses methods-----------------
10320 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10322 Unit
*owner
= GetCharmerOrOwner();
10323 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10326 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10327 data
<< uint8(0); // cast count?
10328 data
<< uint32(spellid
);
10329 data
<< uint8(msg
);
10330 // uint32 for some reason
10331 // uint32 for some reason
10332 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10335 void Unit::SendPetActionFeedback (uint8 msg
)
10337 Unit
* owner
= GetOwner();
10338 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10341 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10342 data
<< uint8(msg
);
10343 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10346 void Unit::SendPetTalk (uint32 pettalk
)
10348 Unit
* owner
= GetOwner();
10349 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10352 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10353 data
<< uint64(GetGUID());
10354 data
<< uint32(pettalk
);
10355 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10358 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10360 Unit
* owner
= GetOwner();
10361 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10364 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10365 data
<< uint64(GetGUID());
10366 data
<< uint8(0x0); // flags (0x1, 0x2)
10367 data
<< uint32(spellid
);
10368 data
<< uint32(cooltime
);
10370 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10373 void Unit::SendPetClearCooldown (uint32 spellid
)
10375 Unit
* owner
= GetOwner();
10376 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10379 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10380 data
<< uint32(spellid
);
10381 data
<< uint64(GetGUID());
10382 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10385 void Unit::SendPetAIReaction(uint64 guid
)
10387 Unit
* owner
= GetOwner();
10388 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10391 WorldPacket
data(SMSG_AI_REACTION
, 12);
10392 data
<< uint64(guid
) << uint32(00000002);
10393 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10396 ///----------End of Pet responses methods----------
10398 void Unit::StopMoving()
10400 clearUnitState(UNIT_STAT_MOVING
);
10402 // send explicit stop packet
10403 // rely on vmaps here because for exemple stormwind is in air
10404 float z
= MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10405 //if (fabs(GetPositionZ() - z) < 2.0f)
10406 // Relocate(GetPositionX(), GetPositionY(), z);
10407 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10409 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10411 // update position and orientation;
10413 BuildHeartBeatMsg(&data
);
10414 SendMessageToSet(&data
,false);
10417 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10421 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10424 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10426 GetMotionMaster()->MovementExpired(false);
10427 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10429 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10431 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10435 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10437 GetMotionMaster()->MovementExpired(false);
10439 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10441 // restore appropriate movement generator
10443 GetMotionMaster()->MoveChase(getVictim());
10445 GetMotionMaster()->Initialize();
10447 // attack caster if can
10448 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10449 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10450 ((Creature
*)this)->AI()->AttackStart(caster
);
10454 if (GetTypeId() == TYPEID_PLAYER
)
10455 ((Player
*)this)->SetClientControl(this, !apply
);
10458 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10462 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10464 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10466 GetMotionMaster()->MoveConfused();
10470 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10472 GetMotionMaster()->MovementExpired(false);
10474 if (GetTypeId() == TYPEID_UNIT
)
10476 // if in combat restore movement generator
10478 GetMotionMaster()->MoveChase(getVictim());
10482 if(GetTypeId() == TYPEID_PLAYER
)
10483 ((Player
*)this)->SetClientControl(this, !apply
);
10486 bool Unit::IsSitState() const
10488 uint8 s
= getStandState();
10489 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10490 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10491 s
== PLAYER_STATE_SIT
;
10494 bool Unit::IsStandState() const
10496 uint8 s
= getStandState();
10497 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10500 void Unit::SetStandState(uint8 state
)
10502 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10504 if (IsStandState())
10505 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10507 if(GetTypeId()==TYPEID_PLAYER
)
10509 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10510 data
<< (uint8
)state
;
10511 ((Player
*)this)->GetSession()->SendPacket(&data
);
10515 bool Unit::IsPolymorphed() const
10517 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10520 void Unit::SetDisplayId(uint32 modelId
)
10522 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10524 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10526 Pet
*pet
= ((Pet
*)this);
10527 if(!pet
->isControlled())
10529 Unit
*owner
= GetOwner();
10530 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10531 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10535 void Unit::ClearComboPointHolders()
10537 while(!m_ComboPointHolders
.empty())
10539 uint32 lowguid
= *m_ComboPointHolders
.begin();
10541 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10542 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10543 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10545 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10549 void Unit::ClearAllReactives()
10552 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10553 m_reactiveTimer
[i
] = 0;
10555 if (HasAuraState( AURA_STATE_DEFENSE
))
10556 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10557 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10558 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10559 if (HasAuraState( AURA_STATE_CRIT
))
10560 ModifyAuraState(AURA_STATE_CRIT
, false);
10561 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10562 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10564 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10565 ((Player
*)this)->ClearComboPoints();
10568 void Unit::UpdateReactives( uint32 p_time
)
10570 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10572 ReactiveType reactive
= ReactiveType(i
);
10574 if(!m_reactiveTimer
[reactive
])
10577 if ( m_reactiveTimer
[reactive
] <= p_time
)
10579 m_reactiveTimer
[reactive
] = 0;
10581 switch ( reactive
)
10583 case REACTIVE_DEFENSE
:
10584 if (HasAuraState(AURA_STATE_DEFENSE
))
10585 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10587 case REACTIVE_HUNTER_PARRY
:
10588 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10589 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10591 case REACTIVE_CRIT
:
10592 if (HasAuraState(AURA_STATE_CRIT
))
10593 ModifyAuraState(AURA_STATE_CRIT
, false);
10595 case REACTIVE_HUNTER_CRIT
:
10596 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10597 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10599 case REACTIVE_OVERPOWER
:
10600 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10601 ((Player
*)this)->ClearComboPoints();
10609 m_reactiveTimer
[reactive
] -= p_time
;
10614 Unit
* Unit::SelectNearbyTarget() const
10616 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10618 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10619 cell
.SetNoCreate();
10621 std::list
<Unit
*> targets
;
10624 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10625 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10627 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10628 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10630 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10631 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10632 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10635 // remove current target
10637 targets
.remove(getVictim());
10639 // remove not LoS targets
10640 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10642 if(!IsWithinLOSInMap(*tIter
))
10644 std::list
<Unit
*>::iterator tIter2
= tIter
;
10646 targets
.erase(tIter2
);
10652 // no appropriate targets
10653 if(targets
.empty())
10657 uint32 rIdx
= urand(0,targets
.size()-1);
10658 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10659 for(uint32 i
= 0; i
< rIdx
; ++i
)
10665 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10669 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10670 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10674 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10675 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10679 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10682 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10684 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10687 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10689 if (CastingTime
> 7000) CastingTime
= 7000;
10690 if (CastingTime
< 1500) CastingTime
= 1500;
10692 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10693 CastingTime
= 3500;
10695 int32 overTime
= 0;
10697 bool DirectDamage
= false;
10698 bool AreaEffect
= false;
10700 for ( uint32 i
=0; i
<3;i
++)
10702 switch ( spellProto
->Effect
[i
] )
10704 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10705 case SPELL_EFFECT_POWER_DRAIN
:
10706 case SPELL_EFFECT_HEALTH_LEECH
:
10707 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10708 case SPELL_EFFECT_POWER_BURN
:
10709 case SPELL_EFFECT_HEAL
:
10710 DirectDamage
= true;
10712 case SPELL_EFFECT_APPLY_AURA
:
10713 switch ( spellProto
->EffectApplyAuraName
[i
] )
10715 case SPELL_AURA_PERIODIC_DAMAGE
:
10716 case SPELL_AURA_PERIODIC_HEAL
:
10717 case SPELL_AURA_PERIODIC_LEECH
:
10718 if ( GetSpellDuration(spellProto
) )
10719 overTime
= GetSpellDuration(spellProto
);
10722 // -5% per additional effect
10730 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10734 // Combined Spells with Both Over Time and Direct Damage
10735 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10737 // mainly for DoTs which are 3500 here otherwise
10738 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10739 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10740 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10741 // Portion to Over Time
10742 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10744 if ( damagetype
== DOT
)
10745 CastingTime
= uint32(CastingTime
* PtOT
);
10746 else if ( PtOT
< 1.0f
)
10747 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10752 // Area Effect Spells receive only half of bonus
10756 // -5% of total per any additional effect
10757 for ( uint8 i
=0; i
<effects
; ++i
)
10759 if ( CastingTime
> 175 )
10761 CastingTime
-= 175;
10770 return CastingTime
;
10773 void Unit::UpdateAuraForGroup(uint8 slot
)
10775 if(GetTypeId() == TYPEID_PLAYER
)
10777 Player
* player
= (Player
*)this;
10778 if(player
->GetGroup())
10780 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10781 player
->SetAuraUpdateMask(slot
);
10784 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10786 Pet
*pet
= ((Pet
*)this);
10787 if(pet
->isControlled())
10789 Unit
*owner
= GetOwner();
10790 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10792 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10793 pet
->SetAuraUpdateMask(slot
);
10799 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10801 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10802 return float(GetAttackTime(attType
))/1000.0f
;
10804 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10806 return 2.4; // fist attack
10808 switch (Weapon
->GetProto()->InventoryType
)
10810 case INVTYPE_2HWEAPON
:
10812 case INVTYPE_RANGED
:
10813 case INVTYPE_RANGEDRIGHT
:
10814 case INVTYPE_THROWN
:
10816 case INVTYPE_WEAPON
:
10817 case INVTYPE_WEAPONMAINHAND
:
10818 case INVTYPE_WEAPONOFFHAND
:
10820 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10824 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10826 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10827 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10828 if ((*itr
)->GetId() == spell_id
)
10834 bool Unit::IsUnderLastManaUseEffect() const
10836 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10839 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10841 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10843 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10846 player
->SetContestedPvPTimer(30000);
10847 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10849 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10850 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10851 // call MoveInLineOfSight for nearby contested guards
10852 SetVisibility(GetVisibility());
10854 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10856 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10857 // call MoveInLineOfSight for nearby contested guards
10858 SetVisibility(GetVisibility());
10862 void Unit::AddPetAura(PetAura
const* petSpell
)
10864 m_petAuras
.insert(petSpell
);
10865 if(Pet
* pet
= GetPet())
10866 pet
->CastPetAura(petSpell
);
10869 void Unit::RemovePetAura(PetAura
const* petSpell
)
10871 m_petAuras
.erase(petSpell
);
10872 if(Pet
* pet
= GetPet())
10873 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10876 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10878 Pet
* pet
= new Pet(HUNTER_PET
);
10880 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10886 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, this->GetGUID());
10887 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, this->GetGUID());
10888 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,this->getFaction());
10889 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10891 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10892 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10894 if(!pet
->InitStatsForLevel(level
))
10896 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10901 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10902 // this enables pet details window (Shift+P)
10903 pet
->AIM_Initialize();
10904 pet
->InitPetCreateSpells();
10905 pet
->SetHealth(pet
->GetMaxHealth());