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
62 // auraTypes contains attacker auras capable of proc'ing cast auras
63 static Unit::AuraTypeSet
GenerateAttakerProcCastAuraTypes()
65 static Unit::AuraTypeSet auraTypes
;
66 auraTypes
.insert(SPELL_AURA_DUMMY
);
67 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
68 auraTypes
.insert(SPELL_AURA_MOD_HASTE
);
69 auraTypes
.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
73 // auraTypes contains victim auras capable of proc'ing cast auras
74 static Unit::AuraTypeSet
GenerateVictimProcCastAuraTypes()
76 static Unit::AuraTypeSet auraTypes
;
77 auraTypes
.insert(SPELL_AURA_DUMMY
);
78 auraTypes
.insert(SPELL_AURA_PRAYER_OF_MENDING
);
79 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
83 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
84 static Unit::AuraTypeSet
GenerateAttakerProcEffectAuraTypes()
86 static Unit::AuraTypeSet auraTypes
;
87 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_DONE
);
88 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
89 auraTypes
.insert(SPELL_AURA_MOD_CASTING_SPEED
);
90 auraTypes
.insert(SPELL_AURA_MOD_RATING
);
94 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
95 static Unit::AuraTypeSet
GenerateVictimProcEffectAuraTypes()
97 static Unit::AuraTypeSet auraTypes
;
98 auraTypes
.insert(SPELL_AURA_MOD_RESISTANCE
);
99 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
100 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
101 auraTypes
.insert(SPELL_AURA_MOD_BLOCK_PERCENT
);
102 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
106 static Unit::AuraTypeSet attackerProcCastAuraTypes
= GenerateAttakerProcCastAuraTypes();
107 static Unit::AuraTypeSet attackerProcEffectAuraTypes
= GenerateAttakerProcEffectAuraTypes();
109 static Unit::AuraTypeSet victimProcCastAuraTypes
= GenerateVictimProcCastAuraTypes();
110 static Unit::AuraTypeSet victimProcEffectAuraTypes
= GenerateVictimProcEffectAuraTypes();
112 // auraTypes contains auras capable of proc'ing for attacker and victim
113 static Unit::AuraTypeSet
GenerateProcAuraTypes()
115 Unit::AuraTypeSet auraTypes
;
116 auraTypes
.insert(attackerProcCastAuraTypes
.begin(),attackerProcCastAuraTypes
.end());
117 auraTypes
.insert(attackerProcEffectAuraTypes
.begin(),attackerProcEffectAuraTypes
.end());
118 auraTypes
.insert(victimProcCastAuraTypes
.begin(),victimProcCastAuraTypes
.end());
119 auraTypes
.insert(victimProcEffectAuraTypes
.begin(),victimProcEffectAuraTypes
.end());
123 static Unit::AuraTypeSet procAuraTypes
= GenerateProcAuraTypes();
125 bool IsPassiveStackableSpell( uint32 spellId
)
127 if(!IsPassiveSpell(spellId
))
130 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
134 for(int j
= 0; j
< 3; ++j
)
136 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
144 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
146 m_objectType
|= TYPEMASK_UNIT
;
147 m_objectTypeId
= TYPEID_UNIT
;
149 m_updateFlag
= (UPDATEFLAG_LOWGUID
| UPDATEFLAG_HIGHGUID
| UPDATEFLAG_LIVING
| UPDATEFLAG_HAS_POSITION
);
151 m_attackTimer
[BASE_ATTACK
] = 0;
152 m_attackTimer
[OFF_ATTACK
] = 0;
153 m_attackTimer
[RANGED_ATTACK
] = 0;
154 m_modAttackSpeedPct
[BASE_ATTACK
] = 1.0f
;
155 m_modAttackSpeedPct
[OFF_ATTACK
] = 1.0f
;
156 m_modAttackSpeedPct
[RANGED_ATTACK
] = 1.0f
;
162 m_deathState
= ALIVE
;
164 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
165 m_currentSpells
[i
] = NULL
;
169 for(int i
= 0; i
< MAX_TOTEM
; ++i
)
172 m_ObjectSlot
[0] = m_ObjectSlot
[1] = m_ObjectSlot
[2] = m_ObjectSlot
[3] = 0;
174 //m_AurasCheck = 2000;
175 //m_removeAuraTimer = 4;
179 m_Visibility
= VISIBILITY_ON
;
181 m_detectInvisibilityMask
= 0;
182 m_invisibilityMask
= 0;
184 m_ShapeShiftFormSpellId
= 0;
185 m_canModifyStats
= false;
187 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
188 m_spellImmune
[i
].clear();
189 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
191 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
192 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
193 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
194 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
196 // implement 50% base damage from offhand
197 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
199 for (int i
= 0; i
< 3; i
++)
201 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
202 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
204 for (int i
= 0; i
< MAX_STATS
; i
++)
205 m_createStats
[i
] = 0.0f
;
208 m_modMeleeHitChance
= 0.0f
;
209 m_modRangedHitChance
= 0.0f
;
210 m_modSpellHitChance
= 0.0f
;
211 m_baseSpellCritChance
= 5;
216 //m_victimThreat = 0.0f;
217 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
218 m_threatModifier
[i
] = 1.0f
;
220 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
221 m_speed_rate
[i
] = 1.0f
;
225 m_unit_movement_flags
= 0;
227 // remove aurastates allowing special moves
228 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
229 m_reactiveTimer
[i
] = 0;
234 // set current spells as deletable
235 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
237 if (m_currentSpells
[i
])
239 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
240 m_currentSpells
[i
] = NULL
;
244 RemoveAllGameObjects();
245 RemoveAllDynObjects();
247 if(m_charmInfo
) delete m_charmInfo
;
250 void Unit::Update( uint32 p_time
)
252 /*if(p_time > m_AurasCheck)
257 m_AurasCheck -= p_time;*/
259 // WARNING! Order of execution here is important, do not change.
260 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
261 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
262 m_Events
.Update( p_time
);
263 _UpdateSpells( p_time
);
265 // update combat timer only for players and pets
266 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
268 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
269 // targets without stopping half way there and running off.
270 // These flags are reset after target dies or another command is given.
271 if( m_HostilRefManager
.isEmpty() )
273 // m_CombatTimer set at aura start and it will be freeze until aura removing
274 if ( m_CombatTimer
<= p_time
)
277 m_CombatTimer
-= p_time
;
281 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
283 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
286 // update abilities available only for fraction of time
287 UpdateReactives( p_time
);
289 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, GetHealth() < GetMaxHealth()*0.20f
);
290 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, GetHealth() < GetMaxHealth()*0.35f
);
292 i_motionMaster
.UpdateMotion(p_time
);
295 bool Unit::haveOffhandWeapon() const
297 if(GetTypeId() == TYPEID_PLAYER
)
298 return ((Player
*)this)->GetWeaponForAttack(OFF_ATTACK
,true);
303 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player
* player
)
306 if(GetMotionMaster()->GetDestination(x
, y
, z
))
307 SendMonsterMoveWithSpeed(x
, y
, z
, GetUnitMovementFlags(), 0, player
);
310 void Unit::SendMonsterMoveWithSpeed(float x
, float y
, float z
, uint32 MovementFlags
, uint32 transitTime
, Player
* player
)
314 float dx
= x
- GetPositionX();
315 float dy
= y
- GetPositionY();
316 float dz
= z
- GetPositionZ();
318 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
324 double speed
= GetSpeed((MovementFlags
& MOVEMENTFLAG_WALK_MODE
) ? MOVE_WALK
: MOVE_RUN
);
328 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
330 //float orientation = (float)atan2((double)dy, (double)dx);
331 SendMonsterMove(x
, y
, z
, 0, MovementFlags
, transitTime
, player
);
334 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, uint32 MovementFlags
, uint32 Time
, Player
* player
)
336 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
337 data
.append(GetPackGUID());
339 // Point A, starting location
340 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
341 // unknown field - unrelated to orientation
342 // seems to increment about 1000 for every 1.7 seconds
343 // for now, we'll just use mstime
346 data
<< uint8(type
); // unknown
349 case 0: // normal packet
351 case 1: // stop packet
352 SendMessageToSet( &data
, true );
354 case 2: // not used currently
359 case 3: // not used currently
360 data
<< uint64(0); // probably target guid
362 case 4: // not used currently
363 data
<< float(0); // probably orientation
367 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
368 data
<< uint32(MovementFlags
);
370 data
<< Time
; // Time in between points
371 data
<< uint32(1); // 1 single waypoint
372 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
375 player
->GetSession()->SendPacket(&data
);
377 SendMessageToSet( &data
, true );
380 void Unit::SendMonsterMoveByPath(Path
const& path
, uint32 start
, uint32 end
, uint32 MovementFlags
)
382 uint32 traveltime
= uint32(path
.GetTotalLength(start
, end
) * 32);
384 uint32 pathSize
= end
-start
;
386 WorldPacket
data( SMSG_MONSTER_MOVE
, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize
*4*3) );
387 data
.append(GetPackGUID());
388 data
<< GetPositionX();
389 data
<< GetPositionY();
390 data
<< GetPositionZ();
392 // unknown field - unrelated to orientation
393 // seems to increment about 1000 for every 1.7 seconds
394 // for now, we'll just use mstime
398 data
<< uint32( MovementFlags
);
399 data
<< uint32( traveltime
);
400 data
<< uint32( pathSize
);
401 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
403 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
404 SendMessageToSet(&data
, true);
407 void Unit::resetAttackTimer(WeaponAttackType type
)
409 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
412 bool Unit::canReachWithAttack(Unit
*pVictim
) const
415 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
418 return IsWithinDistInMap(pVictim
, reach
);
421 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
423 if (auraType
>= TOTAL_AURAS
) return;
424 AuraList::iterator iter
, next
;
425 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
432 RemoveAurasDueToSpell((*iter
)->GetId());
433 if (!m_modAuras
[auraType
].empty())
434 next
= m_modAuras
[auraType
].begin();
441 bool Unit::HasAuraType(AuraType auraType
) const
443 return (!m_modAuras
[auraType
].empty());
446 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
447 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
449 if(!HasAuraType(auraType
))
452 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
453 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
454 float chance
= float(damage
) / max_dmg
* 100.0f
;
455 if (roll_chance_f(chance
))
456 RemoveSpellsCausingAura(auraType
);
459 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
461 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
464 //You don't lose health from damage taken from another player while in a sanctuary
465 //You still see it in the combat log though
466 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
468 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
469 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
473 // remove affects from victim (including from 0 damage and DoTs)
475 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
477 // remove affects from attacker at any non-DoT damage (including 0 damage)
478 if( damagetype
!= DOT
)
480 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
481 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
484 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
486 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
487 pVictim
->SetStandState(PLAYER_STATE_NONE
);
490 //Script Event damage Deal
491 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
492 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
493 //Script Event damage taken
494 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
495 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
499 // Rage from physical damage received .
500 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
501 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
506 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
507 // root type spells do not dispel the root effect
508 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
509 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
511 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
513 // no xp,health if type 8 /critters/
514 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
516 pVictim
->setDeathState(JUST_DIED
);
517 pVictim
->SetHealth(0);
519 // allow loot only if has loot_id in creature_template
520 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
521 if(cInfo
&& cInfo
->lootid
)
522 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
524 // some critters required for quests
525 if(GetTypeId() == TYPEID_PLAYER
)
526 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
531 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
532 ((Creature
*)pVictim
)->AI()->AttackStart(this);
535 DEBUG_LOG("DealDamageStart");
537 uint32 health
= pVictim
->GetHealth();
538 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
540 // duel ends when player has 1 or less hp
541 bool duel_hasEnded
= false;
542 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
544 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
545 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
548 duel_hasEnded
= true;
551 if(pVictim
!= this && damagetype
!= DOT
)
553 SetInCombatWith(pVictim
);
554 pVictim
->SetInCombatWith(this);
556 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
557 SetContestedPvP(attackedPlayer
);
560 // Rage from Damage made (only from direct weapon damage)
561 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
563 uint32 weaponSpeedHitFactor
;
565 switch(cleanDamage
->attackType
)
569 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
570 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
572 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
574 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
580 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
581 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
583 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
585 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
594 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
596 if(((Player
*)pVictim
)->InBattleGround())
598 Player
*killer
= ((Player
*)this);
599 if(killer
!= ((Player
*)pVictim
))
600 if(BattleGround
*bg
= killer
->GetBattleGround())
601 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
605 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
606 ((Creature
*)pVictim
)->SetLootRecipient(this);
607 if (health
<= damage
)
609 // battleground things
610 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
612 Player
*killed
= ((Player
*)pVictim
);
613 Player
*killer
= NULL
;
614 if(GetTypeId() == TYPEID_PLAYER
)
615 killer
= ((Player
*)this);
616 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
618 Unit
*owner
= GetOwner();
619 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
620 killer
= ((Player
*)owner
);
624 if(BattleGround
*bg
= killed
->GetBattleGround())
625 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
628 DEBUG_LOG("DealDamage: victim just died");
630 // find player: owner of controlled `this` or `this` itself maybe
631 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
633 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
634 player
= ((Creature
*)pVictim
)->GetLootRecipient();
635 // Reward player, his pets, and group/raid members
636 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
637 if(player
&& player
!=pVictim
)
638 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
639 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
641 DEBUG_LOG("DealDamageAttackStop");
644 pVictim
->CombatStop();
645 pVictim
->getHostilRefManager().deleteReferences();
647 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
649 // if talent known but not triggered (check priest class for speedup check)
650 Aura
* spiritOfRedemtionTalentReady
= NULL
;
651 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
652 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
654 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
655 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
657 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
659 spiritOfRedemtionTalentReady
= *itr
;
665 DEBUG_LOG("SET JUST_DIED");
666 if(!spiritOfRedemtionTalentReady
)
667 pVictim
->setDeathState(JUST_DIED
);
669 DEBUG_LOG("DealDamageHealth1");
671 if(spiritOfRedemtionTalentReady
)
673 // save value before aura remove
674 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
676 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
678 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
679 pVictim
->RemoveAllAurasOnDeath();
681 // restore for use at real death
682 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
684 // FORM_SPIRITOFREDEMPTION and related auras
685 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
688 pVictim
->SetHealth(0);
690 // remember victim PvP death for corpse type and corpse reclaim delay
691 // at original death (not at SpiritOfRedemtionTalent timeout)
692 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
693 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
695 // Call KilledUnit for creatures
696 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
697 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
700 if ( pVictim
->GetTypeId() == TYPEID_PLAYER
)
702 if(GetTypeId() == TYPEID_UNIT
)
703 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
, GetEntry());
704 else if(GetTypeId() == TYPEID_PLAYER
)
705 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
, 1);
708 // 10% durability loss on death
709 // clean InHateListOf
710 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
712 // only if not player and not controlled by player pet. And not at BG
713 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
715 DEBUG_LOG("We are dead, loosing 10 percents durability");
716 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
717 // durability lost message
718 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
719 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
722 else // creature died
724 DEBUG_LOG("DealDamageNotPlayer");
725 Creature
*cVictim
= (Creature
*)pVictim
;
727 if(!cVictim
->isPet())
729 cVictim
->DeleteThreatList();
730 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
732 // Call creature just died function
734 cVictim
->AI()->JustDied(this);
736 // Dungeon specific stuff, only applies to players killing creatures
737 if(cVictim
->GetInstanceId())
739 Map
*m
= cVictim
->GetMap();
740 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
741 // TODO: do instance binding anyway if the charmer/owner is offline
743 if(m
->IsDungeon() && creditedPlayer
)
745 if(m
->IsRaid() || m
->IsHeroic())
747 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
748 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
752 // the reset time is set but not added to the scheduler
753 // until the players leave the instance
754 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
755 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
756 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
762 // last damage from non duel opponent or opponent controlled creature
765 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
766 Player
*he
= (Player
*)pVictim
;
770 he
->duel
->opponent
->CombatStopWithPets(true);
771 he
->CombatStopWithPets(true);
773 he
->DuelComplete(DUEL_INTERUPTED
);
776 else // if (health <= damage)
778 DEBUG_LOG("DealDamageAlive");
780 pVictim
->ModifyHealth(- (int32
)damage
);
782 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
783 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
785 uint32 procVictim
= PROC_FLAG_NONE
;
787 // if just dropped below 20% (for CheatDeath)
788 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
789 procVictim
= PROC_FLAG_LOW_HEALTH
;
791 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
794 if(damagetype
!= DOT
)
798 // if have target and damage pVictim just call AI reaction
799 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
800 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
804 // if not have main target then attack state with target (including AI call)
805 //start melee attacks only after melee hit
806 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
810 // polymorphed and other negative transformed cases
811 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
812 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
814 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
815 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
817 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
819 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
820 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
822 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
824 else // victim is a player
826 // Rage from damage received
827 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
829 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
830 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
833 // random durability for items (HIT TAKEN)
834 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
836 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
837 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
841 if(GetTypeId()==TYPEID_PLAYER
)
843 // random durability for items (HIT DONE)
844 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
846 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
847 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
851 // TODO: Store auras by interrupt flag to speed this up.
852 AuraMap
& vAuras
= pVictim
->GetAuras();
853 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
855 const SpellEntry
*se
= i
->second
->GetSpellProto();
857 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
860 if (se
->procFlags
& (1<<3))
862 if (!roll_chance_i(se
->procChance
))
867 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
868 // FIXME: this may cause the auras with proc chance to be rerolled several times
869 next
= vAuras
.begin();
874 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
876 if( damagetype
!= DOT
)
878 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
880 // skip channeled spell (processed differently below)
881 if (i
== CURRENT_CHANNELED_SPELL
)
884 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
885 if(spell
->getState() == SPELL_STATE_PREPARING
)
890 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
892 if (spell
->getState() == SPELL_STATE_CASTING
)
894 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
895 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
897 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
898 spell
->DelayedChannel();
900 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
902 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
903 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
906 else if (spell
->getState() == SPELL_STATE_DELAYED
)
907 // break channeled spell in delayed state on damage
909 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
910 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
915 // last damage from duel opponent
918 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
919 Player
*he
= (Player
*)pVictim
;
925 he
->duel
->opponent
->CombatStopWithPets(true);
926 he
->CombatStopWithPets(true);
928 he
->CastSpell(he
, 7267, true); // beg
929 he
->DuelComplete(DUEL_WON
);
933 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
938 void Unit::CastStop(uint32 except_spellid
)
940 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
941 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
942 InterruptSpell(i
,false);
945 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
947 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
951 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
955 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
958 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
962 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
967 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
969 if(!originalCaster
&& triggeredByAura
)
970 originalCaster
= triggeredByAura
->GetCasterGUID();
972 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
974 SpellCastTargets targets
;
975 targets
.setUnitTarget( Victim
);
976 spell
->m_CastItem
= castItem
;
977 spell
->prepare(&targets
, triggeredByAura
);
980 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
982 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
986 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
990 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggeredByAura
, originalCaster
);
993 void Unit::CastCustomSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
997 sLog
.outError("CastCustomSpell: unknown spell");
1002 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1004 if(!originalCaster
&& triggeredByAura
)
1005 originalCaster
= triggeredByAura
->GetCasterGUID();
1007 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1010 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
1013 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1016 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1018 SpellCastTargets targets
;
1019 targets
.setUnitTarget( Victim
);
1020 spell
->m_CastItem
= castItem
;
1021 spell
->prepare(&targets
, triggeredByAura
);
1024 // used for scripting
1025 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1027 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1031 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()));
1035 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
1038 // used for scripting
1039 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1043 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1048 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1050 if(!originalCaster
&& triggeredByAura
)
1051 originalCaster
= triggeredByAura
->GetCasterGUID();
1053 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1055 SpellCastTargets targets
;
1056 targets
.setDestination(x
, y
, z
);
1057 spell
->m_CastItem
= castItem
;
1058 spell
->prepare(&targets
, triggeredByAura
);
1061 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1063 // TODO this in only generic way, check for exceptions
1064 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1066 // Per-damage class calculation
1067 switch (spellInfo
->DmgClass
)
1069 // Melee and Ranged Spells
1070 case SPELL_DAMAGE_CLASS_RANGED
:
1071 case SPELL_DAMAGE_CLASS_MELEE
:
1073 // Calculate physical outcome
1074 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1076 //Used to store the Hit Outcome
1077 cleanDamage
->hitOutCome
= outcome
;
1079 // Return miss/evade first (sends miss message)
1082 case MELEE_HIT_EVADE
:
1084 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1088 case MELEE_HIT_MISS
:
1090 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1093 if(GetTypeId()== TYPEID_PLAYER
)
1094 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1096 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1101 // Hitinfo, Victimstate
1102 uint32 hitInfo
= HITINFO_NORMALSWING
;
1103 VictimState victimState
= VICTIMSTATE_NORMAL
;
1106 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1108 // apply spellmod to Done damage
1109 if(Player
* modOwner
= GetSpellModOwner())
1110 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1112 //Calculate armor mitigation
1113 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1115 // random durability for main hand weapon (ABSORB)
1116 if(damageAfterArmor
< *damage
)
1117 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1118 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1119 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1121 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1122 *damage
= damageAfterArmor
;
1127 // Calculate damage bonus
1128 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1134 case MELEE_HIT_BLOCK_CRIT
:
1135 case MELEE_HIT_CRIT
:
1137 uint32 bonusDmg
= *damage
;
1139 // Apply crit_damage bonus
1140 if(Player
* modOwner
= GetSpellModOwner())
1141 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1143 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1144 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1145 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1146 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1147 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1149 *damage
+= bonusDmg
;
1151 // Resilience - reduce crit damage
1152 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1154 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1155 cleanDamage
->damage
+= resilienceReduction
;
1156 *damage
-= resilienceReduction
;
1160 hitInfo
|= HITINFO_CRITICALHIT
;
1162 ModifyAuraState(AURA_STATE_CRIT
, true);
1163 StartReactiveTimer( REACTIVE_CRIT
);
1165 if(getClass()==CLASS_HUNTER
)
1167 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1168 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1171 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1173 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1174 if (blocked_amount
>= *damage
)
1176 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1177 victimState
= VICTIMSTATE_BLOCKS
;
1178 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1183 // To Help Calculate Rage
1184 cleanDamage
->damage
+= blocked_amount
;
1185 *damage
= *damage
- blocked_amount
;
1188 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1189 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1191 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1194 ((Player
*)pVictim
)->UpdateDefense();
1196 // random durability for main hand weapon (BLOCK)
1197 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1198 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1203 case MELEE_HIT_PARRY
:
1205 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1207 victimState
= VICTIMSTATE_PARRY
;
1209 // Counter-attack ( explained in Unit::DoAttackDamage() )
1210 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1212 // Get attack timers
1213 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1214 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1216 // Reduce attack time
1217 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1219 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1220 float percent60
= 3 * percent20
;
1221 if(offtime
> percent20
&& offtime
<= percent60
)
1223 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1225 else if(offtime
> percent60
)
1227 offtime
-= 2 * percent20
;
1228 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1233 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1234 float percent60
= 3 * percent20
;
1235 if(basetime
> percent20
&& basetime
<= percent60
)
1237 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1239 else if(basetime
> percent60
)
1241 basetime
-= 2 * percent20
;
1242 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1247 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1249 // Update victim defense ?
1250 ((Player
*)pVictim
)->UpdateDefense();
1252 // random durability for main hand weapon (PARRY)
1253 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1254 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1258 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1260 // Mongoose bite - set only Counterattack here
1261 if (pVictim
->getClass() == CLASS_HUNTER
)
1263 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1264 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1268 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1269 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1273 case MELEE_HIT_DODGE
:
1275 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1276 ((Player
*)pVictim
)->UpdateDefense();
1278 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1280 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1281 victimState
= VICTIMSTATE_DODGE
;
1284 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1287 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1289 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1290 StartReactiveTimer( REACTIVE_OVERPOWER
);
1294 if (pVictim
->getClass() != CLASS_ROGUE
)
1296 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1297 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1301 case MELEE_HIT_BLOCK
:
1303 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1304 if (blocked_amount
>= *damage
)
1306 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1307 victimState
= VICTIMSTATE_BLOCKS
;
1308 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1313 // To Help Calculate Rage
1314 cleanDamage
->damage
+= blocked_amount
;
1315 *damage
= *damage
- blocked_amount
;
1318 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1319 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1321 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1324 ((Player
*)pVictim
)->UpdateDefense();
1326 // random durability for main hand weapon (BLOCK)
1327 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1328 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1332 case MELEE_HIT_EVADE
: // already processed early
1333 case MELEE_HIT_MISS
: // already processed early
1334 case MELEE_HIT_GLANCING
:
1335 case MELEE_HIT_CRUSHING
:
1336 case MELEE_HIT_NORMAL
:
1340 // do all damage=0 cases here
1342 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1347 case SPELL_DAMAGE_CLASS_NONE
:
1348 case SPELL_DAMAGE_CLASS_MAGIC
:
1350 // Calculate damage bonus
1351 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1353 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1356 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1358 // Resilience - reduce crit damage
1359 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1361 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1362 if(*damage
> damage_reduction
)
1363 *damage
-= damage_reduction
;
1368 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1370 // spell proc all magic damage==0 case in this function
1374 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1375 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1377 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1384 // TODO this in only generic way, check for exceptions
1385 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1388 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1390 if(!this || !pVictim
)
1392 if(!isAlive() || !pVictim
->isAlive())
1395 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1399 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1403 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1405 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1408 // Calculate absorb & resists
1412 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1414 //No more damage left, target absorbed and/or resisted all damage
1415 if (damage
> absorb
+ resist
)
1416 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1419 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1422 HitInfo
|= HITINFO_ABSORB
;
1425 HitInfo
|= HITINFO_RESIST
;
1426 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1430 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1435 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1438 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1439 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1441 // Actual log sent to client
1442 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1445 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1446 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1450 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1451 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1454 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1460 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1463 if(cleanDamage
.damage
)
1464 // Rage from damage received.
1465 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1466 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1472 void Unit::HandleEmoteCommand(uint32 anim_id
)
1474 WorldPacket
data( SMSG_EMOTE
, 12 );
1475 data
<< uint32(anim_id
);
1476 data
<< uint64(GetGUID());
1477 SendMessageToSet(&data
, true);
1480 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1482 uint32 newdamage
= 0;
1483 float armor
= pVictim
->GetArmor();
1484 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1485 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1487 if (armor
<0.0f
) armor
=0.0f
;
1489 float tmpvalue
= 0.0f
;
1490 if(getLevel() <= 59) //Level 1-59
1491 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1492 else if(getLevel() < 70) //Level 60-69
1493 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1495 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1499 if(tmpvalue
> 0.75f
)
1501 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1503 return (newdamage
> 1) ? newdamage
: 1;
1506 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1508 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1511 // Magic damage, check for resists
1512 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1514 // Get base victim resistance for school
1515 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1516 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1517 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1519 tmpvalue2
*= (float)(0.15f
/ getLevel());
1520 if (tmpvalue2
< 0.0f
)
1522 if (tmpvalue2
> 0.75f
)
1524 uint32 ran
= urand(0, 100);
1525 uint32 faq
[4] = {24,6,4,6};
1528 for (uint8 i
= 0; i
< 4; i
++)
1530 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1536 if (damagetype
== DOT
&& m
== 4)
1537 *resist
+= uint32(damage
- 1);
1539 *resist
+= uint32(damage
* m
/ 4);
1540 if(*resist
> damage
)
1546 int32 RemainingDamage
= damage
- *resist
;
1548 // absorb without mana cost
1549 int32 reflectDamage
= 0;
1550 Aura
* reflectAura
= NULL
;
1551 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1552 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1556 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1560 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1562 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1564 if (pVictim
->GetHealth() <= RemainingDamage
)
1566 int32 chance
= (*i
)->GetModifier()->m_amount
;
1567 if (roll_chance_i(chance
))
1569 pVictim
->CastSpell(pVictim
,31231,true);
1570 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1572 // with health > 10% lost health until health==10%, in other case no losses
1573 uint32 health10
= pVictim
->GetMaxHealth()/10;
1574 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1580 int32 currentAbsorb
;
1583 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1585 if(Unit
* caster
= (*i
)->GetCaster())
1587 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1588 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1590 switch((*k
)->GetModifier()->m_miscvalue
)
1592 case 5065: // Rank 1
1593 case 5064: // Rank 2
1594 case 5063: // Rank 3
1595 case 5062: // Rank 4
1596 case 5061: // Rank 5
1598 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1599 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1601 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1614 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1616 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1617 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1618 next
= vSchoolAbsorb
.begin();
1622 currentAbsorb
= RemainingDamage
;
1623 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1626 RemainingDamage
-= currentAbsorb
;
1628 // do not cast spells while looping auras; auras can get invalid otherwise
1630 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1632 // absorb by mana cost
1633 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1634 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1638 // check damage school mask
1639 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1642 int32 currentAbsorb
;
1643 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1644 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1646 currentAbsorb
= RemainingDamage
;
1648 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1649 if(Player
*modOwner
= GetSpellModOwner())
1650 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1652 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1653 if (currentAbsorb
> maxAbsorb
)
1654 currentAbsorb
= maxAbsorb
;
1656 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1657 if((*i
)->GetModifier()->m_amount
<= 0)
1659 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1660 next
= vManaShield
.begin();
1663 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1664 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1666 RemainingDamage
-= currentAbsorb
;
1669 // only split damage if not damaging yourself
1672 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1673 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1677 // check damage school mask
1678 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1681 // Damage can be splitted only if aura has an alive caster
1682 Unit
*caster
= (*i
)->GetCaster();
1683 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1686 int32 currentAbsorb
;
1687 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1688 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1690 currentAbsorb
= RemainingDamage
;
1692 RemainingDamage
-= currentAbsorb
;
1694 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1696 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1697 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1700 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1701 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1705 // check damage school mask
1706 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1709 // Damage can be splitted only if aura has an alive caster
1710 Unit
*caster
= (*i
)->GetCaster();
1711 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1714 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1716 RemainingDamage
-= splitted
;
1718 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1720 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1721 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1725 *absorb
= damage
- RemainingDamage
- *resist
;
1728 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
)
1730 MeleeHitOutcome outcome
;
1732 // If is casted Melee spell, calculate like physical
1734 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1736 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1738 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1739 pVictim
->AddThreat(this, 0.0f
);
1742 case MELEE_HIT_EVADE
:
1744 *hitInfo
|= HITINFO_MISS
;
1746 cleanDamage
->damage
= 0;
1749 case MELEE_HIT_MISS
:
1751 *hitInfo
|= HITINFO_MISS
;
1753 cleanDamage
->damage
= 0;
1754 if(GetTypeId()== TYPEID_PLAYER
)
1755 ((Player
*)this)->UpdateWeaponSkill(attType
);
1760 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1761 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1762 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1764 // -probability is between 0% and 40%
1766 float Probability
= 20;
1768 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1769 if( pVictim
->getLevel() < 30 )
1770 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1772 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1773 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1775 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1777 if(Probability
> 40.0f
)
1778 Probability
= 40.0f
;
1780 if(roll_chance_f(Probability
))
1781 CastSpell(pVictim
, 1604, true);
1784 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1785 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1787 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1789 // random durability for main hand weapon (ABSORB)
1790 if(damageAfterArmor
< *damage
)
1791 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1792 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1793 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1795 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1796 *damage
= damageAfterArmor
;
1799 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1800 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1802 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1803 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1807 case MELEE_HIT_BLOCK_CRIT
:
1808 case MELEE_HIT_CRIT
:
1810 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| HITINFO_UNK2
;
1814 crit_bonus
= *damage
;
1816 // Apply crit_damage bonus for melee spells
1819 if(Player
* modOwner
= GetSpellModOwner())
1820 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1822 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1823 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1824 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1825 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1826 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1829 *damage
+= crit_bonus
;
1831 uint32 resilienceReduction
= 0;
1833 if(attType
== RANGED_ATTACK
)
1835 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1836 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1837 // Resilience - reduce crit damage
1838 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1839 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1843 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1844 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1845 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1846 // Resilience - reduce crit damage
1847 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1848 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1851 *damage
-= resilienceReduction
;
1852 cleanDamage
->damage
+= resilienceReduction
;
1854 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1855 ((Player
*)this)->UpdateWeaponSkill(attType
);
1857 ModifyAuraState(AURA_STATE_CRIT
, true);
1858 StartReactiveTimer( REACTIVE_CRIT
);
1860 if(getClass()==CLASS_HUNTER
)
1862 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1863 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1866 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1868 *blocked_amount
= pVictim
->GetShieldBlockValue();
1870 if (pVictim
->GetUnitBlockChance())
1871 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1873 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1875 //Only set VICTIMSTATE_BLOCK on a full block
1876 if (*blocked_amount
>= uint32(*damage
))
1878 *victimState
= VICTIMSTATE_BLOCKS
;
1879 *blocked_amount
= uint32(*damage
);
1882 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1885 ((Player
*)pVictim
)->UpdateDefense();
1887 // random durability for main hand weapon (BLOCK)
1888 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1889 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1892 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1893 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1897 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1900 case MELEE_HIT_PARRY
:
1902 if(attType
== RANGED_ATTACK
) //range attack - no parry
1904 outcome
= MELEE_HIT_NORMAL
;
1908 cleanDamage
->damage
+= *damage
;
1910 *victimState
= VICTIMSTATE_PARRY
;
1912 // instant (maybe with small delay) counter attack
1914 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1915 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1917 // after parry nearest next attack time will reduced at %40 from full attack time.
1918 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1919 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1921 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1922 float percent60
= 3*percent20
;
1923 // set to 20% if in range 20%...20+40% of full time
1924 if(offtime
> percent20
&& offtime
<= percent60
)
1926 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1928 // decrease at %40 from full time
1929 else if(offtime
> percent60
)
1931 offtime
-= 2*percent20
;
1932 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1938 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1939 float percent60
= 3*percent20
;
1940 // set to 20% if in range 20%...20+40% of full time
1941 if(basetime
> percent20
&& basetime
<= percent60
)
1943 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1945 // decrease at %40 from full time
1946 else if(basetime
> percent60
)
1948 basetime
-= 2*percent20
;
1949 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1955 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1957 // Update victim defense ?
1958 ((Player
*)pVictim
)->UpdateDefense();
1960 // random durability for main hand weapon (PARRY)
1961 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1962 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1965 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1967 if (pVictim
->getClass() == CLASS_HUNTER
)
1969 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1970 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1974 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1975 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1978 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1981 case MELEE_HIT_DODGE
:
1983 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1985 outcome
= MELEE_HIT_NORMAL
;
1989 cleanDamage
->damage
+= *damage
;
1991 *victimState
= VICTIMSTATE_DODGE
;
1993 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1994 ((Player
*)pVictim
)->UpdateDefense();
1996 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1998 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
2000 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
2001 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2005 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
2007 ((Player
*)this)->AddComboPoints(pVictim
, 1);
2008 StartReactiveTimer( REACTIVE_OVERPOWER
);
2011 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2014 case MELEE_HIT_BLOCK
:
2016 *blocked_amount
= pVictim
->GetShieldBlockValue();
2018 if (pVictim
->GetUnitBlockChance())
2019 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2021 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2023 //Only set VICTIMSTATE_BLOCK on a full block
2024 if (*blocked_amount
>= uint32(*damage
))
2026 *victimState
= VICTIMSTATE_BLOCKS
;
2027 *blocked_amount
= uint32(*damage
);
2030 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2033 ((Player
*)pVictim
)->UpdateDefense();
2035 // random durability for main hand weapon (BLOCK)
2036 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2037 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2040 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2041 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2045 case MELEE_HIT_GLANCING
:
2047 float reducePercent
= 1.0f
; //damage factor
2049 // calculate base values and mods
2050 float baseLowEnd
= 1.3;
2051 float baseHighEnd
= 1.2;
2052 switch(getClass()) // lowering base values for casters
2064 float maxLowEnd
= 0.6;
2065 switch(getClass()) // upper for melee classes
2069 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2073 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2074 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2075 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2077 // apply max/min bounds
2078 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2080 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2083 if ( highEnd
< 0.2f
) //high end limits
2085 if ( highEnd
> 0.99f
)
2088 if(lowEnd
> highEnd
) // prevent negative range size
2091 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2093 *damage
= uint32(reducePercent
* *damage
);
2094 cleanDamage
->damage
+= *damage
;
2095 *hitInfo
|= HITINFO_GLANCING
;
2098 case MELEE_HIT_CRUSHING
:
2100 // 150% normal damage
2101 *damage
+= (*damage
/ 2);
2102 cleanDamage
->damage
= *damage
;
2103 *hitInfo
|= HITINFO_CRUSHING
;
2104 // TODO: victimState, victim animation?
2111 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2112 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2114 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2115 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2118 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2119 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2121 cleanDamage
->damage
+= *blocked_amount
;
2123 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2125 //*hitInfo = 0x00010020;
2126 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2128 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2132 // update at damage Judgement aura duration that applied by attacker at victim
2135 AuraMap
const& vAuras
= pVictim
->GetAuras();
2136 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2138 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2139 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2140 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2142 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2143 (*itr
).second
->SendAuraUpdate(false);
2148 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2150 // victim's damage shield
2151 // yet another hack to fix crashes related to the aura getting removed during iteration
2152 std::set
<Aura
*> alreadyDone
;
2153 uint32 removedAuras
= pVictim
->m_removedAuras
;
2154 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2155 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2158 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2160 alreadyDone
.insert(*i
);
2161 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2162 if (pVictim
->m_removedAuras
> removedAuras
)
2164 removedAuras
= pVictim
->m_removedAuras
;
2165 next
= vDamageShields
.begin();
2171 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2173 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2176 if (!pVictim
->isAlive())
2179 if(IsNonMeleeSpellCasted(false))
2183 if (attType
== BASE_ATTACK
)
2184 hitInfo
= HITINFO_NORMALSWING2
;
2185 else if (attType
== OFF_ATTACK
)
2186 hitInfo
= HITINFO_LEFTSWING
;
2188 return; // ignore ranged case
2190 uint32 extraAttacks
= m_extraAttacks
;
2192 // melee attack spell casted at main hand attack only
2193 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2195 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2197 // not recent extra attack only at any non extra attack (melee spell case)
2198 if(!extra
&& extraAttacks
)
2200 while(m_extraAttacks
)
2202 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2203 if(m_extraAttacks
> 0)
2211 VictimState victimState
= VICTIMSTATE_NORMAL
;
2213 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2214 uint32 blocked_dmg
= 0;
2215 uint32 absorbed_dmg
= 0;
2216 uint32 resisted_dmg
= 0;
2218 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2220 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2222 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2224 // not recent extra attack only at any non extra attack (miss case)
2225 if(!extra
&& extraAttacks
)
2227 while(m_extraAttacks
)
2229 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2230 if(m_extraAttacks
> 0)
2238 uint32 damage
= CalculateDamage (attType
, false);
2240 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2242 if (hitInfo
& HITINFO_MISS
)
2244 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2248 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2250 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2251 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2255 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2257 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2259 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2260 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2264 if (GetTypeId() == TYPEID_PLAYER
)
2265 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2266 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2268 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2269 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2271 // extra attack only at any non extra attack (normal case)
2272 if(!extra
&& extraAttacks
)
2274 while(m_extraAttacks
)
2276 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2277 if(m_extraAttacks
> 0)
2283 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2285 // Miss chance based on melee
2286 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2288 // Critical hit chance
2289 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2290 // this is to avoid compiler issue when declaring variables inside if
2291 float block_chance
, parry_chance
, dodge_chance
;
2293 // cannot be dodged/parried/blocked
2294 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2296 block_chance
= 0.0f
;
2297 parry_chance
= 0.0f
;
2298 dodge_chance
= 0.0f
;
2302 // parry can be avoided only by some abilities
2303 parry_chance
= pVictim
->GetUnitParryChance();
2304 // block might be bypassed by it as well
2305 block_chance
= pVictim
->GetUnitBlockChance();
2306 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2307 dodge_chance
= pVictim
->GetUnitDodgeChance();
2310 // Only players can have Talent&Spell bonuses
2311 if (GetTypeId() == TYPEID_PLAYER
)
2313 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2314 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2316 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents for speed
2318 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2319 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2321 // can't be dodged rogue finishing move
2322 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2324 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2326 dodge_chance
= 0.0f
;
2335 if(Player
* modOwner
= GetSpellModOwner())
2336 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2338 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2340 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);
2343 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2345 // This is only wrapper
2347 // Miss chance based on melee
2348 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2350 // Critical hit chance
2351 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2353 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2354 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2355 float block_chance
= pVictim
->GetUnitBlockChance();
2356 float parry_chance
= pVictim
->GetUnitParryChance();
2358 // Useful if want to specify crit & miss chances for melee, else it could be removed
2359 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2361 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);
2364 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
2366 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2367 return MELEE_HIT_EVADE
;
2369 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2370 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2372 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2373 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2375 // bonus from skills is 0.04%
2376 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2377 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2378 int32 sum
= 0, tmp
= 0;
2379 int32 roll
= urand (0, 10000);
2381 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2383 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2387 if (tmp
> 0 && roll
< (sum
+= tmp
))
2389 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2390 return MELEE_HIT_MISS
;
2393 // always crit against a sitting target (except 0 crit chance)
2394 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2396 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2397 return MELEE_HIT_CRIT
;
2402 // only players can't dodge if attacker is behind
2403 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2405 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2409 // Reduce dodge chance by attacker expertise rating
2410 if (GetTypeId() == TYPEID_PLAYER
)
2411 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2413 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2414 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2417 if ( (tmp
> 0) // check if unit _can_ dodge
2418 && ((tmp
-= skillBonus
) > 0)
2419 && roll
< (sum
+= tmp
))
2421 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2422 return MELEE_HIT_DODGE
;
2426 // parry & block chances
2428 // check if attack comes from behind, nobody can parry or block if attacker is behind
2429 if (!pVictim
->HasInArc(M_PI
,this))
2431 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2435 // Reduce parry chance by attacker expertise rating
2436 if (GetTypeId() == TYPEID_PLAYER
)
2437 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2439 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2441 int32 tmp
= int32(parry_chance
);
2442 if ( (tmp
> 0) // check if unit _can_ parry
2443 && ((tmp
-= skillBonus
) > 0)
2444 && (roll
< (sum
+= tmp
)))
2446 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2447 return MELEE_HIT_PARRY
;
2451 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2454 if ( (tmp
> 0) // check if unit _can_ block
2455 && ((tmp
-= skillBonus
) > 0)
2456 && (roll
< (sum
+= tmp
)))
2459 tmp
= crit_chance
+ skillBonus2
;
2460 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2462 if ( roll_chance_i(tmp
/100))
2464 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2465 return MELEE_HIT_BLOCK_CRIT
;
2468 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2469 return MELEE_HIT_BLOCK
;
2475 tmp
= crit_chance
+ skillBonus2
;
2477 if (tmp
> 0 && roll
< (sum
+= tmp
))
2479 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2480 return MELEE_HIT_CRIT
;
2483 // 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)
2484 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2485 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2486 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2487 getLevel() < pVictim
->getLevelForTarget(this) )
2489 // cap possible value (with bonuses > max skill)
2490 int32 skill
= attackerWeaponSkill
;
2491 int32 maxskill
= attackerMaxSkillValueForLevel
;
2492 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2494 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2495 tmp
= tmp
> 4000 ? 4000 : tmp
;
2496 if (roll
< (sum
+= tmp
))
2498 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2499 return MELEE_HIT_GLANCING
;
2503 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2505 // mobs can score crushing blows if they're 3 or more levels above victim
2506 // or when their weapon skill is 15 or more above victim's defense skill
2507 tmp
= victimDefenseSkill
;
2508 int32 tmpmax
= victimMaxSkillValueForLevel
;
2509 // having defense above your maximum (from items, talents etc.) has no effect
2510 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2511 // tmp = mob's level * 5 - player's current defense skill
2512 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2515 // add 2% chance per lacking skill point, min. is 15%
2516 tmp
= tmp
* 200 - 1500;
2517 if (roll
< (sum
+= tmp
))
2519 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2520 return MELEE_HIT_CRUSHING
;
2525 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2526 return MELEE_HIT_NORMAL
;
2529 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2531 float min_damage
, max_damage
;
2533 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2534 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2540 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2541 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2544 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2545 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2548 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2549 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2551 // Just for good manner
2559 if (min_damage
> max_damage
)
2561 std::swap(min_damage
,max_damage
);
2564 if(max_damage
== 0.0f
)
2567 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2570 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2572 if(spellProto
->spellLevel
<= 0)
2575 float LvlPenalty
= 0.0f
;
2577 if(spellProto
->spellLevel
< 20)
2578 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2579 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2580 if(LvlFactor
> 1.0f
)
2583 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2586 void Unit::SendAttackStart(Unit
* pVictim
)
2588 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2589 data
<< uint64(GetGUID());
2590 data
<< uint64(pVictim
->GetGUID());
2592 SendMessageToSet(&data
, true);
2593 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2596 void Unit::SendAttackStop(Unit
* victim
)
2601 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2602 data
.append(GetPackGUID());
2603 data
.append(victim
->GetPackGUID()); // can be 0x00...
2604 data
<< uint32(0); // can be 0x1
2605 SendMessageToSet(&data
, true);
2606 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2608 /*if(victim->GetTypeId() == TYPEID_UNIT)
2609 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2613 // Melee based spells can be miss, parry or dodge on this step
2614 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2615 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2617 // Calculate hit chance (more correct for chance mod)
2620 // PvP - PvE melee chances
2621 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2622 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2624 HitChance = 95 - leveldif;
2626 HitChance = 93 - (leveldif - 2) * lchance;
2628 // Hit chance depends from victim auras
2629 if(attType == RANGED_ATTACK)
2630 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2632 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2634 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2635 if(Player *modOwner = GetSpellModOwner())
2636 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2639 float miss_chance= 100.0f - HitChance;
2641 // Bonuses from attacker aura and ratings
2642 if (attType == RANGED_ATTACK)
2643 miss_chance -= m_modRangedHitChance;
2645 miss_chance -= m_modMeleeHitChance;
2647 // bonus from skills is 0.04%
2648 miss_chance -= skillDiff * 0.04f;
2650 // Limit miss chance from 0 to 60%
2651 if (miss_chance < 0.0f)
2653 if (miss_chance > 60.0f)
2658 // Melee based spells hit result calculations
2659 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2661 WeaponAttackType attType = BASE_ATTACK;
2663 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2664 attType = RANGED_ATTACK;
2666 // bonus from skills is 0.04% per skill Diff
2667 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2668 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2669 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2671 uint32 roll = urand (0, 10000);
2672 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2675 uint32 tmp = missChance;
2677 return SPELL_MISS_MISS;
2679 // Same spells cannot be parry/dodge
2680 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2681 return SPELL_MISS_NONE;
2683 // Ranged attack can`t miss too
2684 if (attType == RANGED_ATTACK)
2685 return SPELL_MISS_NONE;
2687 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2690 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2691 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2692 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2694 // Reduce dodge chance by attacker expertise rating
2695 if (GetTypeId() == TYPEID_PLAYER)
2696 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2697 if (dodgeChance < 0)
2700 // Can`t dodge from behind in PvP (but its possible in PvE)
2701 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2704 // Rogue talent`s cant be dodged
2705 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2706 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2708 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2710 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2720 return SPELL_MISS_DODGE;
2723 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2724 // Reduce parry chance by attacker expertise rating
2725 if (GetTypeId() == TYPEID_PLAYER)
2726 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2727 // Can`t parry from behind
2728 if (parryChance < 0 || attackFromBehind)
2733 return SPELL_MISS_PARRY;
2735 return SPELL_MISS_NONE;
2738 // TODO need use unit spell resistances in calculations
2739 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2741 // Can`t miss on dead target (on skinning for example)
2742 if (!pVictim
->isAlive())
2743 return SPELL_MISS_NONE
;
2745 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2746 // PvP - PvE spell misschances per leveldif > 2
2747 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2748 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2750 // Base hit chance from attacker and victim levels
2753 modHitChance
= 96 - leveldif
;
2755 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2757 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2758 if(Player
*modOwner
= GetSpellModOwner())
2759 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2760 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2761 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2762 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2763 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2764 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2765 if (IsAreaOfEffectSpell(spell
))
2766 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2767 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2768 if (IsDispelSpell(spell
))
2769 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2770 // Chance resist mechanic (select max value from every mechanic spell effect)
2771 int32 resist_mech
= 0;
2772 // Get effects mechanic and chance
2773 for(int eff
= 0; eff
< 3; ++eff
)
2775 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2778 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2779 if (resist_mech
< temp
)
2784 modHitChance
-=resist_mech
;
2786 // Chance resist debuff
2787 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2789 int32 HitChance
= modHitChance
* 100;
2790 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2791 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2793 // Decrease hit chance from victim rating bonus
2794 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2795 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2797 if (HitChance
< 100) HitChance
= 100;
2798 if (HitChance
> 9900) HitChance
= 9900;
2800 uint32 rand
= urand(0,10000);
2801 if (rand
> HitChance
)
2802 return SPELL_MISS_RESIST
;
2803 return SPELL_MISS_NONE
;
2806 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2808 // Return evade for units in evade mode
2809 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2810 return SPELL_MISS_EVADE
;
2812 // Check for immune (use charges)
2813 if (pVictim
->IsImmunedToSpell(spell
,true))
2814 return SPELL_MISS_IMMUNE
;
2816 // All positive spells can`t miss
2817 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2818 if (IsPositiveSpell(spell
->Id
))
2819 return SPELL_MISS_NONE
;
2821 // Check for immune (use charges)
2822 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2823 return SPELL_MISS_IMMUNE
;
2825 // Try victim reflect spell
2828 // specialized first
2829 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2830 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2832 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2834 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2835 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2837 if((*i
)->m_procCharges
> 0)
2839 --(*i
)->m_procCharges
;
2840 if((*i
)->m_procCharges
==0)
2841 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2843 return SPELL_MISS_REFLECT
;
2848 // generic reflection
2849 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2850 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2852 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2853 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2855 if((*i
)->m_procCharges
> 0)
2857 --(*i
)->m_procCharges
;
2858 if((*i
)->m_procCharges
==0)
2859 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2861 return SPELL_MISS_REFLECT
;
2866 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2867 for (int i
=0;i
<3;i
++)
2869 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2870 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2871 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2872 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2873 return SPELL_MISS_NONE
;
2876 // TODO need use this code for spell hit result calculation
2877 // now code commented for computability
2878 switch (spell
->DmgClass
)
2880 case SPELL_DAMAGE_CLASS_RANGED
:
2881 case SPELL_DAMAGE_CLASS_MELEE
:
2882 // return MeleeSpellHitResult(pVictim, spell);
2883 return SPELL_MISS_NONE
;
2884 case SPELL_DAMAGE_CLASS_NONE
:
2885 case SPELL_DAMAGE_CLASS_MAGIC
:
2886 return MagicSpellHitResult(pVictim
, spell
);
2888 return SPELL_MISS_NONE
;
2891 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2896 // Base misschance 5%
2897 float misschance
= 5.0f
;
2899 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2900 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2902 bool isNormal
= false;
2903 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2905 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2911 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2921 // PvP : PvE melee misschances per leveldif > 2
2922 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2924 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2928 // Hit chance from attacker based on ratings and auras
2929 float m_modHitChance
;
2930 if (attType
== RANGED_ATTACK
)
2931 m_modHitChance
= m_modRangedHitChance
;
2933 m_modHitChance
= m_modMeleeHitChance
;
2936 misschance
+= (leveldif
- m_modHitChance
);
2938 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2940 // Hit chance for victim based on ratings
2941 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2943 if (attType
== RANGED_ATTACK
)
2944 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2946 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2949 // Modify miss chance by victim auras
2950 if(attType
== RANGED_ATTACK
)
2951 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2953 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2955 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2956 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2957 misschance
-= skillBonus
* 0.04f
;
2959 // Limit miss chance from 0 to 60%
2960 if ( misschance
< 0.0f
)
2962 if ( misschance
> 60.0f
)
2968 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2970 if(GetTypeId() == TYPEID_PLAYER
)
2972 // in PvP use full skill instead current skill value
2973 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2974 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2975 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2976 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2980 return GetUnitMeleeSkill(target
);
2983 float Unit::GetUnitDodgeChance() const
2985 if(hasUnitState(UNIT_STAT_STUNNED
))
2987 if( GetTypeId() == TYPEID_PLAYER
)
2988 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2991 if(((Creature
const*)this)->isTotem())
2996 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2997 return dodge
> 0.0f
? dodge
: 0.0f
;
3002 float Unit::GetUnitParryChance() const
3004 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3007 float chance
= 0.0f
;
3009 if(GetTypeId() == TYPEID_PLAYER
)
3011 Player
const* player
= (Player
const*)this;
3012 if(player
->CanParry() )
3014 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3016 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3019 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3022 else if(GetTypeId() == TYPEID_UNIT
)
3024 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3027 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3031 return chance
> 0.0f
? chance
: 0.0f
;
3034 float Unit::GetUnitBlockChance() const
3036 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3039 if(GetTypeId() == TYPEID_PLAYER
)
3041 Player
const* player
= (Player
const*)this;
3042 if(player
->CanBlock() )
3044 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3045 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3046 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3048 // is player but has no block ability or no not broken shield equipped
3053 if(((Creature
const*)this)->isTotem())
3058 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3059 return block
> 0.0f
? block
: 0.0f
;
3064 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3068 if(GetTypeId() == TYPEID_PLAYER
)
3073 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3076 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3079 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3081 // Just for good manner
3090 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3094 if(attackType
== RANGED_ATTACK
)
3095 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3097 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3099 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3101 // reduce crit chance from Rating for players
3102 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3104 if (attackType
==RANGED_ATTACK
)
3105 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3107 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3115 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3118 if(GetTypeId() == TYPEID_PLAYER
)
3120 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3122 // feral or unarmed skill only for base attack
3123 if(attType
!= BASE_ATTACK
&& !item
)
3126 if(((Player
*)this)->IsInFeralForm())
3127 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3129 // weapon skill or (unarmed for base attack)
3130 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3132 // in PvP use full skill instead current skill value
3133 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3134 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3135 : ((Player
*)this)->GetSkillValue(skill
);
3136 // Modify value from ratings
3137 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3140 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3141 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3142 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3146 value
= GetUnitMeleeSkill(target
);
3150 void Unit::_UpdateSpells( uint32 time
)
3152 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3153 _UpdateAutoRepeatSpell();
3155 // remove finished spells from current pointers
3156 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3158 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3160 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3161 m_currentSpells
[i
] = NULL
; // remove pointer
3165 // TODO: Find a better way to prevent crash when multiple auras are removed.
3167 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3169 (*i
).second
->SetUpdated(false);
3171 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3177 // prevent double update
3178 if ((*i
).second
->IsUpdated())
3180 (*i
).second
->SetUpdated(true);
3181 (*i
).second
->Update( time
);
3182 // several auras can be deleted due to update
3185 if (m_Auras
.empty()) break;
3186 next
= m_Auras
.begin();
3192 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3196 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3211 if(!m_gameObj
.empty())
3213 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3214 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3217 //(*i)->Update( difftime );
3218 if( !(*ite1
)->isSpawned() )
3220 (*ite1
)->SetOwnerGUID(0);
3221 (*ite1
)->SetRespawnTime(0);
3223 dnext1
= m_gameObj
.erase(ite1
);
3231 void Unit::_UpdateAutoRepeatSpell()
3233 //check "realtime" interrupts
3234 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3236 // cancel wand shoot
3237 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3238 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3239 m_AutoRepeatFirstCast
= true;
3244 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3245 setAttackTimer(RANGED_ATTACK
,500);
3246 m_AutoRepeatFirstCast
= false;
3249 if (isAttackReady(RANGED_ATTACK
))
3251 // Check if able to cast
3252 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3254 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3259 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3260 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3262 // all went good, reset attack
3263 resetAttackTimer(RANGED_ATTACK
);
3267 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3269 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3271 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3273 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3275 // break same type spell if it is not delayed
3276 InterruptSpell(CSpellType
,false);
3278 // special breakage effects:
3281 case CURRENT_GENERIC_SPELL
:
3283 // generic spells always break channeled not delayed spells
3284 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3286 // autorepeat breaking
3287 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3289 // break autorepeat if not Auto Shot
3290 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3291 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3292 m_AutoRepeatFirstCast
= true;
3296 case CURRENT_CHANNELED_SPELL
:
3298 // channel spells always break generic non-delayed and any channeled spells
3299 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3300 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3302 // it also does break autorepeat if not Auto Shot
3303 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3304 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3305 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3308 case CURRENT_AUTOREPEAT_SPELL
:
3310 // only Auto Shoot does not break anything
3311 if (pSpell
->m_spellInfo
->Category
== 351)
3313 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3314 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3315 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3317 // special action: set first cast flag
3318 m_AutoRepeatFirstCast
= true;
3323 // other spell types don't break anything now
3327 // current spell (if it is still here) may be safely deleted now
3328 if (m_currentSpells
[CSpellType
])
3329 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3331 // set new current spell
3332 m_currentSpells
[CSpellType
] = pSpell
;
3333 pSpell
->SetReferencedFromCurrent(true);
3336 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3338 assert(spellType
< CURRENT_MAX_SPELL
);
3340 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3342 // send autorepeat cancel message for autorepeat spells
3343 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3345 if(GetTypeId()==TYPEID_PLAYER
)
3346 ((Player
*)this)->SendAutoRepeatCancel();
3349 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3350 m_currentSpells
[spellType
]->cancel();
3351 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3352 m_currentSpells
[spellType
] = NULL
;
3356 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3358 // We don't do loop here to explicitly show that melee spell is excluded.
3359 // Maybe later some special spells will be excluded too.
3361 // generic spells are casted when they are not finished and not delayed
3362 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3363 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3364 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3367 // channeled spells may be delayed, but they are still considered casted
3368 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3369 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3372 // autorepeat spells may be finished or delayed, but they are still considered casted
3373 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3379 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3381 // generic spells are interrupted if they are not finished or delayed
3382 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3384 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3385 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3386 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3387 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3388 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3391 // autorepeat spells are interrupted if they are not finished or delayed
3392 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3394 // send disable autorepeat packet in any case
3395 if(GetTypeId()==TYPEID_PLAYER
)
3396 ((Player
*)this)->SendAutoRepeatCancel();
3398 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3399 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3400 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3401 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3402 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3405 // channeled spells are interrupted if they are not finished, even if they are delayed
3406 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3408 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3409 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3410 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3411 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3415 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3417 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3418 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3419 return m_currentSpells
[i
];
3423 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3425 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3428 void Unit::SetInFront(Unit
const* target
)
3430 SetOrientation(GetAngle(target
));
3433 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3435 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3438 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3441 return c
->canSwim();
3443 return c
->canWalk() || c
->canFly();
3446 bool Unit::IsInWater() const
3448 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3451 bool Unit::IsUnderWater() const
3453 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3456 void Unit::DeMorph()
3458 SetDisplayId(GetNativeDisplayId());
3461 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3465 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3466 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3467 modifier
+= (*i
)->GetModifier()->m_amount
;
3472 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3474 float multiplier
= 1.0f
;
3476 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3477 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3478 multiplier
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3483 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3487 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3488 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3489 if ((*i
)->GetModifier()->m_amount
> modifier
)
3490 modifier
= (*i
)->GetModifier()->m_amount
;
3495 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3499 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3500 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3501 if ((*i
)->GetModifier()->m_amount
< modifier
)
3502 modifier
= (*i
)->GetModifier()->m_amount
;
3507 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3511 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3512 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3514 Modifier
* mod
= (*i
)->GetModifier();
3515 if (mod
->m_miscvalue
& misc_mask
)
3516 modifier
+= mod
->m_amount
;
3521 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3523 float multiplier
= 1.0f
;
3525 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3526 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3528 Modifier
* mod
= (*i
)->GetModifier();
3529 if (mod
->m_miscvalue
& misc_mask
)
3530 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3535 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3539 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3540 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3542 Modifier
* mod
= (*i
)->GetModifier();
3543 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3544 modifier
= mod
->m_amount
;
3550 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3554 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3555 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3557 Modifier
* mod
= (*i
)->GetModifier();
3558 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3559 modifier
= mod
->m_amount
;
3565 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3569 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3570 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3572 Modifier
* mod
= (*i
)->GetModifier();
3573 if (mod
->m_miscvalue
== misc_value
)
3574 modifier
+= mod
->m_amount
;
3579 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3581 float multiplier
= 1.0f
;
3583 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3584 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3586 Modifier
* mod
= (*i
)->GetModifier();
3587 if (mod
->m_miscvalue
== misc_value
)
3588 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3593 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3597 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3598 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3600 Modifier
* mod
= (*i
)->GetModifier();
3601 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3602 modifier
= mod
->m_amount
;
3608 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3612 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3613 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3615 Modifier
* mod
= (*i
)->GetModifier();
3616 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3617 modifier
= mod
->m_amount
;
3623 bool Unit::AddAura(Aura
*Aur
)
3625 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3626 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3627 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3633 if(Aur
->GetTarget() != this)
3635 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3636 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3637 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3642 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3644 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3645 AuraMap::iterator i
= m_Auras
.find( spair
);
3647 // take out same spell
3648 if (i
!= m_Auras
.end())
3650 // passive and persistent auras can stack with themselves any number of times
3651 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3653 // replace aura if next will > spell StackAmount
3654 if(aurSpellInfo
->StackAmount
)
3656 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3657 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3659 // if StackAmount==0 not allow auras from same caster
3662 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3664 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3666 // can be only single (this check done at _each_ aura add
3667 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3672 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3675 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3676 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3677 case SPELL_AURA_PERIODIC_LEECH
:
3678 case SPELL_AURA_PERIODIC_HEAL
:
3679 case SPELL_AURA_OBS_MOD_HEALTH
:
3680 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3681 case SPELL_AURA_PERIODIC_ENERGIZE
:
3682 case SPELL_AURA_OBS_MOD_MANA
:
3683 case SPELL_AURA_POWER_BURN_MANA
:
3685 default: // not allow
3686 // can be only single (this check done at _each_ aura add
3687 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3699 // passive auras stack with all (except passive spell proc auras)
3700 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3701 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3703 if (!RemoveNoStackAurasDueToAura(Aur
))
3706 return false; // couldn't remove conflicting aura with higher rank
3710 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3711 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3713 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3716 Unit
* caster
= Aur
->GetCaster();
3717 if(!caster
) // caster deleted and not required adding scAura
3720 bool restart
= false;
3721 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3722 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3724 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3725 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3727 if ((*itr
)->IsInUse())
3729 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());
3732 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3741 scAuras
.push_back(Aur
);
3747 // add aura, register in lists and arrays
3749 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3750 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3752 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3755 Aur
->ApplyModifier(true,true);
3756 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3760 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3762 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3765 AuraMap::iterator i
,next
;
3766 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3770 uint32 i_spellId
= (*i
).second
->GetId();
3771 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3773 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3775 RemoveAurasDueToSpell(i_spellId
);
3777 if( m_Auras
.empty() )
3780 next
= m_Auras
.begin();
3786 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3791 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3795 uint32 spellId
= Aur
->GetId();
3796 uint32 effIndex
= Aur
->GetEffIndex();
3798 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3800 AuraMap::iterator i
,next
;
3801 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3805 if (!(*i
).second
) continue;
3807 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3812 uint32 i_spellId
= i_spellProto
->Id
;
3814 if(IsPassiveSpell(i_spellId
))
3816 if(IsPassiveStackableSpell(i_spellId
))
3819 // passive non-stackable spells not stackable only with another rank of same spell
3820 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3824 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3826 if(i_spellId
== spellId
) continue;
3828 bool is_triggered_by_spell
= false;
3829 // prevent triggered aura of removing aura that triggered it
3830 for(int j
= 0; j
< 3; ++j
)
3831 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3832 is_triggered_by_spell
= true;
3833 if (is_triggered_by_spell
) continue;
3835 for(int j
= 0; j
< 3; ++j
)
3837 // prevent remove dummy triggered spells at next effect aura add
3838 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggered spell
3840 case SPELL_EFFECT_DUMMY
:
3843 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3848 if(is_triggered_by_spell
)
3851 // prevent remove form main spell by triggered passive spells
3852 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3854 case SPELL_AURA_MOD_SHAPESHIFT
:
3857 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3858 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3859 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3865 if(!is_triggered_by_spell
)
3867 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3869 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3871 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3873 // cannot remove higher rank
3874 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3875 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3878 // Its a parent aura (create this aura in ApplyModifier)
3879 if ((*i
).second
->IsInUse())
3881 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());
3884 RemoveAurasDueToSpell(i_spellId
);
3886 if( m_Auras
.empty() )
3889 next
= m_Auras
.begin();
3891 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3893 // Its a parent aura (create this aura in ApplyModifier)
3894 if ((*i
).second
->IsInUse())
3896 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());
3899 RemoveAurasDueToSpell(i_spellId
);
3901 if( m_Auras
.empty() )
3904 next
= m_Auras
.begin();
3906 // Potions stack aura by aura (elixirs/flask already checked)
3907 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3909 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3911 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3912 return false; // cannot remove higher rank
3914 // Its a parent aura (create this aura in ApplyModifier)
3915 if ((*i
).second
->IsInUse())
3917 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());
3929 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3931 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3932 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3934 if(iter
->second
!=except
)
3937 iter
= m_Auras
.lower_bound(spair
);
3944 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3946 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3948 Aura
*aur
= iter
->second
;
3949 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3951 // Custom dispel case
3952 // Unstable Affliction
3953 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3955 int32 damage
= aur
->GetModifier()->m_amount
*9;
3956 uint64 caster_guid
= aur
->GetCasterGUID();
3959 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3961 // backfire damage and silence
3962 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3964 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3967 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3974 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3976 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3978 Aura
*aur
= iter
->second
;
3979 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3981 int32 basePoints
= aur
->GetBasePoints();
3982 // construct the new aura for the attacker
3983 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3987 // set its duration and maximum duration
3988 // max duration 2 minutes (in msecs)
3989 int32 dur
= aur
->GetAuraDuration();
3990 const int32 max_dur
= 2*MINUTE
*1000;
3991 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3992 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3994 // add the new aura to stealer
3995 stealer
->AddAura(new_aur
);
3997 // Remove aura as dispel
3998 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
4005 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4007 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4009 if (iter
->second
->GetId() == spellId
)
4010 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4016 void Unit::RemoveAurasWithDispelType( DispelType type
)
4018 // Create dispel mask by dispel type
4019 uint32 dispelMask
= GetDispellMask(type
);
4020 // Dispel all existing auras vs current dispel type
4021 AuraMap
& auras
= GetAuras();
4022 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4024 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4025 if( (1<<spell
->Dispel
) & dispelMask
)
4028 RemoveAurasDueToSpell(spell
->Id
);
4029 itr
= auras
.begin();
4036 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4038 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4039 if(iter
!= m_Auras
.end())
4043 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4045 for (int i
= 0; i
< 3; ++i
)
4046 RemoveAura(spellId
,i
,except
);
4049 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4051 for (int k
=0; k
< 3; ++k
)
4053 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4054 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4056 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4059 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4067 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4069 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4071 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4078 void Unit::RemoveNotOwnSingleTargetAuras()
4080 // single target auras from other casters
4081 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4083 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4089 // single target auras at other targets
4090 AuraList
& scAuras
= GetSingleCastAuras();
4091 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4094 if (aura
->GetTarget()!=this)
4096 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4097 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4098 iter
= scAuras
.begin();
4106 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4108 if (IsSingleTargetSpell((*i
).second
->GetSpellProto()))
4110 if(Unit
* caster
= (*i
).second
->GetCaster())
4112 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4113 scAuras
.remove((*i
).second
);
4117 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4122 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4124 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
4127 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4128 Aura
* Aur
= i
->second
;
4130 Aur
->SetRemoveMode(mode
);
4131 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4132 // remove aura from list before to prevent deleting it before
4134 ++m_removedAuras
; // internal count used by unit update
4136 // Status unsummoned at aura remove
4137 Totem
* statue
= NULL
;
4138 if(IsChanneledSpell(Aur
->GetSpellProto()))
4139 if(Unit
* caster
= Aur
->GetCaster())
4140 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4141 statue
= ((Totem
*)caster
);
4143 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4144 Aur
->ApplyModifier(false,true);
4151 // only way correctly remove all auras from list
4152 if( m_Auras
.empty() )
4155 i
= m_Auras
.begin();
4158 void Unit::RemoveAllAuras()
4160 while (!m_Auras
.empty())
4162 AuraMap::iterator iter
= m_Auras
.begin();
4167 void Unit::RemoveAllAurasOnDeath()
4169 // used just after dieing to remove all visible auras
4170 // and disable the mods for the passive ones
4171 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4173 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4174 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4180 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4182 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4183 if (iter
!= m_Auras
.end())
4185 if (iter
->second
->GetAuraDuration() < delaytime
)
4186 iter
->second
->SetAuraDuration(0);
4188 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4189 iter
->second
->SendAuraUpdate(false);
4190 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4194 void Unit::_RemoveAllAuraMods()
4196 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4198 (*i
).second
->ApplyModifier(false);
4202 void Unit::_ApplyAllAuraMods()
4204 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4206 (*i
).second
->ApplyModifier(true);
4210 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4212 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4213 if (iter
!= m_Auras
.end())
4214 return iter
->second
;
4218 void Unit::AddDynObject(DynamicObject
* dynObj
)
4220 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4223 void Unit::RemoveDynObject(uint32 spellid
)
4225 if(m_dynObjGUIDs
.empty())
4227 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4229 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4232 i
= m_dynObjGUIDs
.erase(i
);
4234 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4237 i
= m_dynObjGUIDs
.erase(i
);
4244 void Unit::RemoveAllDynObjects()
4246 while(!m_dynObjGUIDs
.empty())
4248 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4251 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4255 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4257 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4259 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4262 i
= m_dynObjGUIDs
.erase(i
);
4266 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4273 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4275 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4277 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4280 i
= m_dynObjGUIDs
.erase(i
);
4284 if (dynObj
->GetSpellId() == spellId
)
4291 void Unit::AddGameObject(GameObject
* gameObj
)
4293 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4294 m_gameObj
.push_back(gameObj
);
4295 gameObj
->SetOwnerGUID(GetGUID());
4298 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4300 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4302 // GO created by some spell
4303 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4305 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4306 // Need activate spell use for owner
4307 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4308 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4310 gameObj
->SetOwnerGUID(0);
4311 m_gameObj
.remove(gameObj
);
4314 gameObj
->SetRespawnTime(0);
4319 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4321 if(m_gameObj
.empty())
4323 std::list
<GameObject
*>::iterator i
, next
;
4324 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4327 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4329 (*i
)->SetOwnerGUID(0);
4332 (*i
)->SetRespawnTime(0);
4336 next
= m_gameObj
.erase(i
);
4343 void Unit::RemoveAllGameObjects()
4345 // remove references to unit
4346 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4348 (*i
)->SetOwnerGUID(0);
4349 (*i
)->SetRespawnTime(0);
4351 i
= m_gameObj
.erase(i
);
4355 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4357 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4358 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4359 data
.append(target
->GetPackGUID());
4360 data
.append(GetPackGUID());
4361 data
<< uint32(SpellID
);
4362 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4363 data
<< uint32(0); // wotlk
4364 data
<< uint8(damageSchoolMask
); // spell school
4365 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4366 data
<< uint32(Resist
); // resist
4367 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
4368 data
<< uint8(0); // unk isFromAura
4369 data
<< uint32(Blocked
); // blocked
4370 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4371 data
<< uint8(0); // isDebug?
4372 SendMessageToSet( &data
, true );
4375 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4377 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4378 data
<< uint32(spellID
);
4379 data
<< uint64(GetGUID());
4380 data
<< uint8(0); // can be 0 or 1
4381 data
<< uint32(1); // target count
4382 // for(i = 0; i < target count; ++i)
4383 data
<< uint64(target
->GetGUID()); // target GUID
4384 data
<< uint8(missInfo
);
4386 SendMessageToSet(&data
, true);
4389 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4391 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4393 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4394 data
<< uint32(HitInfo
); // flags
4395 data
.append(GetPackGUID());
4396 data
.append(target
->GetPackGUID());
4397 data
<< uint32(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);// damage
4398 data
<< uint32(0); // overkill value
4400 data
<< (uint8
)SwingType
; // count?
4402 // for(i = 0; i < SwingType; ++i)
4403 data
<< (uint32
)damageSchoolMask
;
4404 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4405 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4408 if(HitInfo
& (HITINFO_ABSORB
| HITINFO_ABSORB2
))
4410 // for(i = 0; i < SwingType; ++i)
4411 data
<< uint32(AbsorbDamage
);
4415 if(HitInfo
& (HITINFO_RESIST
| HITINFO_RESIST2
))
4417 // for(i = 0; i < SwingType; ++i)
4418 data
<< uint32(Resist
);
4422 data
<< (uint8
)TargetState
;
4426 if(HitInfo
& HITINFO_BLOCK
)
4428 data
<< uint32(BlockedAmount
);
4431 if(HitInfo
& HITINFO_UNK3
)
4436 if(HitInfo
& HITINFO_UNK1
)
4447 for(uint8 i
= 0; i
< 5; ++i
)
4455 SendMessageToSet( &data
, true );
4458 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4460 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4462 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4464 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4465 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4466 // That is the question though if it's fully correct
4467 if(procSpell
&& !isTriggeredSpell
)
4469 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4471 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4472 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4473 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4474 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4475 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4477 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4479 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4480 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4481 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4482 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4483 attType
= RANGED_ATTACK
;
4486 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4487 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4489 // Not much to do if no flags are set.
4492 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4493 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4494 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4497 // Now go on with a victim's events'n'auras
4498 // Not much to do if no flags are set or there is no victim
4499 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4501 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4502 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4503 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4507 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4512 uint32 procAttacker
= PROC_FLAG_NONE
;
4513 uint32 procVictim
= PROC_FLAG_NONE
;
4517 case MELEE_HIT_EVADE
:
4519 case MELEE_HIT_MISS
:
4520 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4522 procAttacker
= PROC_FLAG_MISS
;
4525 case MELEE_HIT_BLOCK_CRIT
:
4526 case MELEE_HIT_CRIT
:
4527 if(spellCasted
&& attType
== BASE_ATTACK
)
4529 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4530 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4531 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4533 procVictim
|= PROC_FLAG_BLOCK
;
4534 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4537 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4539 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4540 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4544 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4545 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4548 case MELEE_HIT_PARRY
:
4549 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4550 procVictim
= PROC_FLAG_PARRY
;
4552 case MELEE_HIT_BLOCK
:
4553 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4554 procVictim
= PROC_FLAG_BLOCK
;
4556 case MELEE_HIT_DODGE
:
4557 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4558 procVictim
= PROC_FLAG_DODGE
;
4560 case MELEE_HIT_CRUSHING
:
4561 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4563 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4564 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4568 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4569 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4573 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4575 procAttacker
= PROC_FLAG_HIT_MELEE
;
4576 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4580 procAttacker
= PROC_FLAG_HIT_RANGED
;
4581 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4587 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4589 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4590 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4593 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4595 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4597 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4598 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4600 uint32 triggered_spell_id
= 0;
4601 Unit
* target
= pVictim
;
4602 int32 basepoints0
= 0;
4604 switch(hasteSpell
->SpellFamilyName
)
4606 case SPELLFAMILY_ROGUE
:
4608 switch(hasteSpell
->Id
)
4614 target
= SelectNearbyTarget();
4617 basepoints0
= damage
;
4618 triggered_spell_id
= 22482;
4626 // processed charge only counting case
4627 if(!triggered_spell_id
)
4630 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4634 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4639 if(!target
|| target
!=this && !target
->isAlive())
4642 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4646 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4648 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4650 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4651 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4656 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4658 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4659 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4661 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4662 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4664 uint32 triggered_spell_id
= 0;
4665 Unit
* target
= pVictim
;
4666 int32 basepoints0
= 0;
4668 switch(dummySpell
->SpellFamilyName
)
4670 case SPELLFAMILY_GENERIC
:
4672 switch (dummySpell
->Id
)
4678 // prevent damage back from weapon special attacks
4679 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4682 // return damage % to attacker but < 50% own total health
4683 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4684 if(basepoints0
> GetMaxHealth()/2)
4685 basepoints0
= GetMaxHealth()/2;
4687 triggered_spell_id
= 25997;
4695 // prevent chain of triggered spell from same triggered spell
4696 if(procSpell
&& procSpell
->Id
==26654)
4699 target
= SelectNearbyTarget();
4703 triggered_spell_id
= 26654;
4709 if (!procSpell
|| procSpell
->Id
== 24659)
4711 // Need remove one 24659 aura
4712 RemoveSingleAuraFromStack(24659, 0);
4713 RemoveSingleAuraFromStack(24659, 1);
4716 // Restless Strength
4719 // Need remove one 24662 aura
4720 RemoveSingleAuraFromStack(24662, 0);
4723 // Adaptive Warding (Frostfire Regalia set)
4731 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4732 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4734 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4736 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4746 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4748 case SPELL_SCHOOL_NORMAL
:
4749 case SPELL_SCHOOL_HOLY
:
4750 return false; // ignored
4751 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4752 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4753 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4754 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4755 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4763 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4771 for(int j
= 0; j
< 3; ++j
)
4773 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4782 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4784 case SPELL_SCHOOL_NORMAL
:
4785 return false; // ignore
4786 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4787 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4788 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4789 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4790 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4791 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4799 // Mana Leech (Passive) (Priest Pet Aura)
4803 target
= GetOwner();
4807 basepoints0
= int32(damage
* 2.5f
); // manaregen
4808 triggered_spell_id
= 34650;
4814 // Cast finish spell at last charge
4815 if (triggeredByAura
->m_procCharges
> 1)
4819 triggered_spell_id
= 33494;
4822 // Twisted Reflection (boss spell)
4824 triggered_spell_id
= 21064;
4826 // Vampiric Aura (boss spell)
4829 basepoints0
= 3 * damage
; // 300%
4830 if (basepoints0
< 0)
4833 triggered_spell_id
= 31285;
4837 // Aura of Madness (Darkmoon Card: Madness trinket)
4838 //=====================================================
4839 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4840 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4841 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4842 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4843 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4844 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4845 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4846 // 41011 Martyr Complex: +35 stamina (All classes)
4847 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4848 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4851 if(GetTypeId() != TYPEID_PLAYER
)
4854 // Select class defined buff
4857 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4858 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4860 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4861 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4864 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4865 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4867 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4868 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4871 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4872 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4873 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4874 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4876 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4877 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4880 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4882 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4883 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4891 if (roll_chance_i(10))
4892 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4896 // TODO: need find item for aura and triggered spells
4897 // Sunwell Exalted Caster Neck (??? neck)
4898 // cast ??? Light's Wrath if Exalted by Aldor
4899 // cast ??? Arcane Bolt if Exalted by Scryers*/
4901 return false; // disable for while
4904 if(GetTypeId() != TYPEID_PLAYER)
4907 // Get Aldor reputation rank
4908 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4911 triggered_spell_id = ???
4914 // Get Scryers reputation rank
4915 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4917 triggered_spell_id = ???
4922 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4923 // cast 45479 Light's Wrath if Exalted by Aldor
4924 // cast 45429 Arcane Bolt if Exalted by Scryers
4927 if(GetTypeId() != TYPEID_PLAYER
)
4930 // Get Aldor reputation rank
4931 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4934 triggered_spell_id
= 45479;
4937 // Get Scryers reputation rank
4938 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4940 triggered_spell_id
= 45429;
4945 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4946 // cast 45480 Light's Strength if Exalted by Aldor
4947 // cast 45428 Arcane Strike if Exalted by Scryers
4950 if(GetTypeId() != TYPEID_PLAYER
)
4953 // Get Aldor reputation rank
4954 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4957 triggered_spell_id
= 45480;
4960 // Get Scryers reputation rank
4961 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4963 triggered_spell_id
= 45428;
4968 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4969 // cast 45431 Arcane Insight if Exalted by Aldor
4970 // cast 45432 Light's Ward if Exalted by Scryers
4973 if(GetTypeId() != TYPEID_PLAYER
)
4976 // Get Aldor reputation rank
4977 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4980 triggered_spell_id
= 45432;
4983 // Get Scryers reputation rank
4984 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4987 triggered_spell_id
= 45431;
4992 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4993 // cast 45478 Light's Salvation if Exalted by Aldor
4994 // cast 45430 Arcane Surge if Exalted by Scryers
4997 if(GetTypeId() != TYPEID_PLAYER
)
5000 // Get Aldor reputation rank
5001 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
5004 triggered_spell_id
= 45478;
5007 // Get Scryers reputation rank
5008 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5010 triggered_spell_id
= 45430;
5018 case SPELLFAMILY_MAGE
:
5021 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5023 if (getPowerType() != POWER_MANA
)
5027 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5029 triggered_spell_id
= 29442;
5032 // Master of Elements
5033 if (dummySpell
->SpellIconID
== 1920)
5039 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5040 if( basepoints0
<=0 )
5044 triggered_spell_id
= 29077;
5047 switch(dummySpell
->Id
)
5056 switch (dummySpell
->Id
)
5058 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5059 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5060 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5061 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5062 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5064 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5068 triggered_spell_id
= 12654;
5074 //last charge and crit
5075 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5077 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5078 return true; // charge counting (will removed)
5081 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5082 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5087 case SPELLFAMILY_WARRIOR
:
5090 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5092 // check attack comes not from behind
5093 if (!HasInArc(M_PI
, pVictim
))
5096 triggered_spell_id
= 22858;
5101 case SPELLFAMILY_WARLOCK
:
5103 // Seed of Corruption
5104 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5106 Modifier
* mod
= triggeredByAura
->GetModifier();
5107 // if damage is more than need or target die from damage deal finish spell
5108 // FIX ME: not triggered currently at death
5109 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5111 // remember guid before aura delete
5112 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5114 // Remove aura (before cast for prevent infinite loop handlers)
5115 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5117 // Cast finish spell (triggeredByAura already not exist!)
5118 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5119 return true; // no hidden cooldown
5123 mod
->m_amount
-=damage
;
5126 // Seed of Corruption (Mobs cast) - no die req
5127 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5129 Modifier
* mod
= triggeredByAura
->GetModifier();
5130 // if damage is more than need deal finish spell
5131 if( mod
->m_amount
<= damage
)
5133 // remember guid before aura delete
5134 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5136 // Remove aura (before cast for prevent infinite loop handlers)
5137 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5139 // Cast finish spell (triggeredByAura already not exist!)
5140 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5141 return true; // no hidden cooldown
5144 mod
->m_amount
-=damage
;
5147 switch(dummySpell
->Id
)
5154 triggered_spell_id
= 17941;
5163 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5165 triggered_spell_id
= 30294;
5168 // Shadowflame (Voidheart Raiment set bonus)
5171 triggered_spell_id
= 37379;
5174 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5182 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5183 triggered_spell_id
= 37382;
5186 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5189 triggered_spell_id
= 37378;
5195 case SPELLFAMILY_PRIEST
:
5198 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5200 if(!pVictim
|| !pVictim
->isAlive())
5203 // pVictim is caster of aura
5204 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5208 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5209 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5210 return true; // no hidden cooldown
5212 switch(dummySpell
->Id
)
5217 if(!pVictim
|| !pVictim
->isAlive())
5220 // pVictim is caster of aura
5221 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5225 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5226 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5227 return true; // no hidden cooldown
5229 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5232 // Shadow Word: Pain
5233 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5234 triggered_spell_id
= 40441;
5236 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5237 triggered_spell_id
= 40440;
5244 // Oracle Healing Bonus ("Garments of the Oracle" set)
5248 basepoints0
= int32(damage
* 10/100);
5250 triggered_spell_id
= 26170;
5253 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5256 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5260 basepoints0
= int32(damage
* 2 / 100);
5262 triggered_spell_id
= 39373;
5265 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5268 triggered_spell_id
= 28810;
5274 case SPELLFAMILY_DRUID
:
5276 switch(dummySpell
->Id
)
5278 // Healing Touch (Dreamwalker Raiment set)
5282 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5284 triggered_spell_id
= 28742;
5287 // Healing Touch Refund (Idol of Longevity trinket)
5291 triggered_spell_id
= 28848;
5294 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5299 triggered_spell_id
= 37238;
5302 // Druid Tier 6 Trinket
5308 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5310 triggered_spell_id
= 40445;
5314 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5316 triggered_spell_id
= 40446;
5319 // Mangle (cat/bear)
5320 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5322 triggered_spell_id
= 40452;
5328 if (!roll_chance_f(chance
))
5337 // Deadly Interrupt Effect
5338 triggered_spell_id
= 32747;
5344 case SPELLFAMILY_ROGUE
:
5346 switch(dummySpell
->Id
)
5348 // Deadly Throw Interrupt
5351 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5355 triggered_spell_id
= 32747;
5360 if( dummySpell
->SpellIconID
== 2116 )
5365 // only rogue's finishing moves (maybe need additional checks)
5366 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5367 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5371 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5372 if(basepoints0
<= 0)
5376 triggered_spell_id
= 31663;
5381 case SPELLFAMILY_HUNTER
:
5383 // Thrill of the Hunt
5384 if ( dummySpell
->SpellIconID
== 2236 )
5390 basepoints0
= procSpell
->manaCost
* 40/100;
5391 if(basepoints0
<= 0)
5395 triggered_spell_id
= 34720;
5400 case SPELLFAMILY_PALADIN
:
5402 // Seal of Righteousness - melee proc dummy
5403 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5405 if(GetTypeId() != TYPEID_PLAYER
)
5409 switch (triggeredByAura
->GetId())
5411 case 21084: spellId
= 25742; break; // Rank 1
5412 case 20287: spellId
= 25740; break; // Rank 2
5413 case 20288: spellId
= 25739; break; // Rank 3
5414 case 20289: spellId
= 25738; break; // Rank 4
5415 case 20290: spellId
= 25737; break; // Rank 5
5416 case 20291: spellId
= 25736; break; // Rank 6
5417 case 20292: spellId
= 25735; break; // Rank 7
5418 case 20293: spellId
= 25713; break; // Rank 8
5419 case 27155: spellId
= 27156; break; // Rank 9
5421 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5424 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5425 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5427 float damageBasePoints
;
5428 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5430 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5432 // one hand weapon/no weapon
5433 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5435 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5437 // apply damage bonuses manually
5438 if(damagePoint
>= 0)
5439 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5441 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5442 return true; // no hidden cooldown
5444 // Seal of Blood do damage trigger
5445 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5447 switch(triggeredByAura
->GetEffIndex())
5450 // prevent chain triggering
5451 if(procSpell
&& procSpell
->Id
==31893 )
5454 triggered_spell_id
= 31893;
5459 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5461 triggered_spell_id
= 32221;
5467 switch(dummySpell
->Id
)
5469 // Holy Power (Redemption Armor set)
5475 // Set class defined buff
5476 switch (pVictim
->getClass())
5482 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5486 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5490 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5493 triggered_spell_id
= 28790; // Increases the friendly target's armor
5503 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5506 triggered_spell_id
= 31803;
5513 // if healed by another unit (pVictim)
5518 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5520 triggered_spell_id
= 31786;
5523 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5531 // Flash of light/Holy light
5532 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5534 triggered_spell_id
= 40471;
5538 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5540 triggered_spell_id
= 40472;
5546 if (!roll_chance_f(chance
))
5554 case SPELLFAMILY_SHAMAN
:
5556 switch(dummySpell
->Id
)
5558 // Totemic Power (The Earthshatterer set)
5564 // Set class defined buff
5565 switch (pVictim
->getClass())
5571 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5575 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5579 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5582 triggered_spell_id
= 28827; // Increases the friendly target's armor
5589 // Lesser Healing Wave (Totem of Flowing Water Relic)
5593 triggered_spell_id
= 28850;
5596 // Windfury Weapon (Passive) 1-5 Ranks
5599 if(GetTypeId()!=TYPEID_PLAYER
)
5602 if(!castItem
|| !castItem
->IsEquipped())
5605 // custom cooldown processing case
5606 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5610 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5612 case 283: spellId
= 33757; break; //1 Rank
5613 case 284: spellId
= 33756; break; //2 Rank
5614 case 525: spellId
= 33755; break; //3 Rank
5615 case 1669:spellId
= 33754; break; //4 Rank
5616 case 2636:spellId
= 33727; break; //5 Rank
5619 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5620 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5625 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5626 if(!windfurySpellEntry
)
5628 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5632 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5635 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5637 // Value gained from additional AP
5638 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5639 triggered_spell_id
= 33750;
5644 // Value gained from additional AP
5645 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5646 triggered_spell_id
= 25504;
5649 // apply cooldown before cast to prevent processing itself
5651 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5654 for ( uint32 i
= 0; i
<2; ++i
)
5655 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5659 // Shaman Tier 6 Trinket
5666 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5668 triggered_spell_id
= 40465; // Lightning Bolt
5671 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5673 triggered_spell_id
= 40465; // Lesser Healing Wave
5676 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5678 triggered_spell_id
= 40466; // Stormstrike
5684 if (!roll_chance_f(chance
))
5693 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5695 if(GetTypeId() != TYPEID_PLAYER
)
5699 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5701 triggered_spell_id
= 379;
5704 // Lightning Overload
5705 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5707 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5710 // custom cooldown processing case
5711 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5715 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5716 switch (procSpell
->Id
)
5719 case 403: spellId
= 45284; break; // Rank 1
5720 case 529: spellId
= 45286; break; // Rank 2
5721 case 548: spellId
= 45287; break; // Rank 3
5722 case 915: spellId
= 45288; break; // Rank 4
5723 case 943: spellId
= 45289; break; // Rank 5
5724 case 6041: spellId
= 45290; break; // Rank 6
5725 case 10391: spellId
= 45291; break; // Rank 7
5726 case 10392: spellId
= 45292; break; // Rank 8
5727 case 15207: spellId
= 45293; break; // Rank 9
5728 case 15208: spellId
= 45294; break; // Rank 10
5729 case 25448: spellId
= 45295; break; // Rank 11
5730 case 25449: spellId
= 45296; break; // Rank 12
5732 case 421: spellId
= 45297; break; // Rank 1
5733 case 930: spellId
= 45298; break; // Rank 2
5734 case 2860: spellId
= 45299; break; // Rank 3
5735 case 10605: spellId
= 45300; break; // Rank 4
5736 case 25439: spellId
= 45301; break; // Rank 5
5737 case 25442: spellId
= 45302; break; // Rank 6
5739 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5742 // No thread generated mod
5743 SpellModifier
*mod
= new SpellModifier
;
5744 mod
->op
= SPELLMOD_THREAT
;
5746 mod
->type
= SPELLMOD_PCT
;
5747 mod
->spellId
= dummySpell
->Id
;
5749 mod
->lastAffected
= NULL
;
5750 mod
->mask
= 0x0000000000000003LL
;
5752 ((Player
*)this)->AddSpellMod(mod
, true);
5754 // Remove cooldown (Chain Lightning - have Category Recovery time)
5755 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5756 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5758 // Hmmm.. in most case spells already set half basepoints but...
5759 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5761 // 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.
5762 // So - no add changes :)
5763 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5765 ((Player
*)this)->AddSpellMod(mod
, false);
5767 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5768 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5778 // processed charge only counting case
5779 if(!triggered_spell_id
)
5782 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5786 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5791 if(!target
|| target
!=this && !target
->isAlive())
5794 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5798 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5800 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5802 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5803 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5808 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5810 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5812 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5813 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5815 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5816 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5817 int32 basepoints0
= 0;
5819 switch(auraSpellInfo
->SpellFamilyName
)
5821 case SPELLFAMILY_GENERIC
:
5823 switch(auraSpellInfo
->Id
)
5825 // Aegis of Preservation
5827 //Aegis Heal (instead non-existed triggered spell)
5828 triggered_spell_id
= 23781;
5831 // Elune's Touch (moonkin mana restore)
5834 // Elune's Touch (instead non-existed triggered spell)
5835 triggered_spell_id
= 33926;
5836 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5843 // only for cast with mana price
5844 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5846 break; // fall through to normal cast
5851 // at melee hit call std triggered spell
5852 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5853 break; // fall through to normal cast
5855 // Mark of Conquest - else (at range hit) called custom case
5856 triggered_spell_id
= 39557;
5862 return true; // nothing to do
5863 // Forgotten Knowledge (Blade of Wizardry)
5865 // only for harmful enemy targeted spell
5866 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5868 break; // fall through to normal cast
5869 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5872 // proc only at non-crit hits
5873 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5875 break; // fall through to normal cast
5877 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5883 //only periodic damage can trigger spell
5885 for(int j
= 0; j
< 3; ++j
)
5887 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5888 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5889 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5898 break; // fall through to normal cast
5900 // Evasive Maneuvers (Commendation of Kael'thas)
5903 // damage taken that reduces below 35% health
5904 // does NOT mean you must have been >= 35% before
5905 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5907 break; // fall through to normal cast
5911 switch(triggered_spell_id
)
5916 // applied only for main target
5917 if(!pVictim
|| pVictim
!= getVictim())
5920 // continue normal case
5923 // Shamanistic Rage triggered spell
5925 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5930 case SPELLFAMILY_MAGE
:
5932 switch(auraSpellInfo
->SpellIconID
)
5936 //Blazing Speed (instead non-existed triggered spell)
5937 triggered_spell_id
= 31643;
5941 switch(auraSpellInfo
->Id
)
5943 // Persistent Shield (Scarab Brooch)
5945 basepoints0
= int32(damage
* 0.15f
);
5950 case SPELLFAMILY_WARRIOR
:
5953 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5955 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5956 //and effect[1]==TriggerSpell
5957 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5959 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5962 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5963 break; // fall through to normal cast
5967 case SPELLFAMILY_WARLOCK
:
5970 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5972 // last case for Hellfire that damage caster also but don't must stun caster
5973 if( pVictim
== this )
5978 switch (triggeredByAura
->GetId())
5980 case 18096: chance
= 13.0f
; break;
5981 case 18073: chance
= 26.0f
; break;
5983 if (!roll_chance_f(chance
))
5986 // Pyroclasm (instead non-existed triggered spell)
5987 triggered_spell_id
= 18093;
5992 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5995 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5996 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5998 //Improved Drain Soul
5999 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
6001 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
6002 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
6005 triggered_spell_id
= 18371;
6013 break; // fall through to normal cast
6017 case SPELLFAMILY_PRIEST
:
6020 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6022 switch (triggeredByAura
->GetSpellProto()->Id
)
6024 case 27811: triggered_spell_id
= 27813; break;
6025 case 27815: triggered_spell_id
= 27817; break;
6026 case 27816: triggered_spell_id
= 27818; break;
6028 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6032 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6033 basepoints0
= heal_amount
/3;
6038 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
[0]==7958)
6040 switch(triggeredByAura
->GetSpellProto()->Id
)
6043 triggered_spell_id
= 28377; break; // Rank 1
6045 triggered_spell_id
= 28378; break; // Rank 2
6047 triggered_spell_id
= 28379; break; // Rank 3
6049 triggered_spell_id
= 28380; break; // Rank 4
6051 triggered_spell_id
= 28381; break; // Rank 5
6053 triggered_spell_id
= 28382; break; // Rank 6
6055 triggered_spell_id
= 28385; break; // Rank 7
6057 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6065 case SPELLFAMILY_DRUID
:
6067 switch(auraSpellInfo
->Id
)
6069 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6072 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6074 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6075 triggered_spell_id
= 34299;
6078 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6085 triggered_spell_id
=37340; break;// Ursine Blessing
6087 triggered_spell_id
=37341; break;// Feline Blessing
6089 triggered_spell_id
=37342; break;// Slyvan Blessing
6091 triggered_spell_id
=37343; break;// Lunar Blessing
6093 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6104 case SPELLFAMILY_ROGUE
:
6106 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6108 switch(auraSpellInfo
->SpellIconID
)
6113 // skip non offhand attacks
6114 if(attackType
!=OFF_ATTACK
)
6116 break; // fall through to normal cast
6122 case SPELLFAMILY_PALADIN
:
6124 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6126 switch(auraSpellInfo
->Id
)
6128 // Lightning Capacitor
6131 // trinket ProcTriggerSpell but for safe checks for player
6132 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6135 if(((Player
*)this)->HasSpellCooldown(37657))
6139 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6140 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6141 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6145 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6146 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6147 if((*itr
)->GetId()==37658)
6150 // release at 3 aura in stack
6152 return true; // main triggered spell casted anyway
6154 RemoveAurasDueToSpell(37658);
6155 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6160 // Healing Trance (instead non-existed triggered spell)
6161 triggered_spell_id
= 37706;
6164 // HoTs on Heals (Fel Reaver's Piston trinket)
6167 // at direct heal effect
6168 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6171 // single proc at time
6172 AuraList
const& scAuras
= GetSingleCastAuras();
6173 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6174 if((*itr
)->GetId()==triggered_spell_id
)
6177 // positive cast at victim instead self
6182 switch(auraSpellInfo
->SpellIconID
)
6186 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6194 // procspell is triggered spell but we need mana cost of original casted spell
6195 uint32 originalSpellId
= procSpell
->Id
;
6198 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6200 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6202 switch(procSpell
->Id
)
6204 case 25914: originalSpellId
= 20473; break;
6205 case 25913: originalSpellId
= 20929; break;
6206 case 25903: originalSpellId
= 20930; break;
6207 case 27175: originalSpellId
= 27174; break;
6208 case 33074: originalSpellId
= 33072; break;
6210 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6216 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6219 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6223 // percent stored in effect 1 (class scripts) base points
6224 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6226 basepoints0
= originalSpell
->manaCost
*percent
/100;
6227 triggered_spell_id
= 20272;
6236 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6238 switch(auraSpellInfo
->SpellIconID
)
6240 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6243 if(!pVictim
|| !pVictim
->isAlive())
6246 switch(triggeredByAura
->GetSpellProto()->Id
)
6249 triggered_spell_id
= 20268; // Rank 1
6252 triggered_spell_id
= 20352; // Rank 2
6255 triggered_spell_id
= 20353; // Rank 3
6258 triggered_spell_id
= 27165; // Rank 4
6261 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6265 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6266 return true; // no hidden cooldown
6268 //Judgement of Light
6271 if(!pVictim
|| !pVictim
->isAlive())
6274 // overwrite non existing triggered spell call in spell.dbc
6275 switch(triggeredByAura
->GetSpellProto()->Id
)
6278 triggered_spell_id
= 20267; // Rank 1
6281 triggered_spell_id
= 20341; // Rank 2
6284 triggered_spell_id
= 20342; // Rank 3
6287 triggered_spell_id
= 20343; // Rank 4
6290 triggered_spell_id
= 27163; // Rank 5
6293 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6296 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6297 return true; // no hidden cooldown
6301 // custom check for proc spell
6302 switch(auraSpellInfo
->Id
)
6304 // Bonus Healing (item spell)
6307 if(!pVictim
|| !pVictim
->isAlive())
6310 // bonus if health < 50%
6311 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6314 // cast at target positive spell
6319 switch(triggered_spell_id
)
6323 // prevent chain of triggered spell from same triggered spell
6324 if(procSpell
&& procSpell
->Id
==20424)
6330 case SPELLFAMILY_SHAMAN
:
6332 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6334 switch(auraSpellInfo
->SpellIconID
)
6338 switch(auraSpellInfo
->Id
)
6340 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6342 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6343 triggered_spell_id
= 23552;
6347 case 23552: // Lightning Shield - trigger shield damage
6349 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6350 triggered_spell_id
= 27635;
6357 // Mana Surge (Shaman T1 bonus)
6363 basepoints0
= procSpell
->manaCost
* 35/100;
6364 triggered_spell_id
= 23571;
6371 if(GetTypeId()!=TYPEID_PLAYER
)
6374 // damage taken that reduces below 30% health
6375 // does NOT mean you must have been >= 30% before
6376 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6379 triggered_spell_id
= 31616;
6381 // need check cooldown now
6382 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6385 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6387 if(pVictim
&& pVictim
->isAlive())
6388 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6394 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6395 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
[0]==7358)
6402 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
[0]==37)
6404 // overwrite non existing triggered spell call in spell.dbc
6405 switch(triggeredByAura
->GetSpellProto()->Id
)
6408 triggered_spell_id
= 26364; break; // Rank 1
6410 triggered_spell_id
= 26365; break; // Rank 2
6412 triggered_spell_id
= 26366; break; // Rank 3
6414 triggered_spell_id
= 26367; break; // Rank 4
6416 triggered_spell_id
= 26369; break; // Rank 5
6418 triggered_spell_id
= 26370; break; // Rank 6
6420 triggered_spell_id
= 26363; break; // Rank 7
6422 triggered_spell_id
= 26371; break; // Rank 8
6424 triggered_spell_id
= 26372; break; // Rank 9
6426 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6437 // standard non-dummy case
6438 if(!triggered_spell_id
)
6440 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6444 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6448 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6452 // not allow proc extra attack spell at extra attack
6453 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6456 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6460 if(!target
|| target
!=this && !target
->isAlive())
6464 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6466 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6468 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6469 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6474 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6476 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6478 if(!pVictim
|| !pVictim
->isAlive())
6481 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6482 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6484 uint32 triggered_spell_id
= 0;
6488 case 836: // Improved Blizzard (Rank 1)
6490 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6492 triggered_spell_id
= 12484;
6495 case 988: // Improved Blizzard (Rank 2)
6497 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6499 triggered_spell_id
= 12485;
6502 case 989: // Improved Blizzard (Rank 3)
6504 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6506 triggered_spell_id
= 12486;
6509 case 4086: // Improved Mend Pet (Rank 1)
6510 case 4087: // Improved Mend Pet (Rank 2)
6512 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6513 if(!roll_chance_i(chance
))
6516 triggered_spell_id
= 24406;
6519 case 4533: // Dreamwalker Raiment 2 pieces bonus
6522 if (!roll_chance_i(50))
6525 switch (pVictim
->getPowerType())
6527 case POWER_MANA
: triggered_spell_id
= 28722; break;
6528 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6529 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6535 case 4537: // Dreamwalker Raiment 6 pieces bonus
6536 triggered_spell_id
= 28750; // Blessing of the Claw
6538 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6539 triggered_spell_id
= 37445; // Mana Surge
6544 if(!triggered_spell_id
)
6547 // standard non-dummy case
6548 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6552 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6556 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6559 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6561 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6562 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6567 void Unit::setPowerType(Powers new_powertype
)
6569 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6571 if(GetTypeId() == TYPEID_PLAYER
)
6573 if(((Player
*)this)->GetGroup())
6574 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6576 else if(((Creature
*)this)->isPet())
6578 Pet
*pet
= ((Pet
*)this);
6579 if(pet
->isControlled())
6581 Unit
*owner
= GetOwner();
6582 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6583 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6587 switch(new_powertype
)
6593 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6594 SetPower( POWER_RAGE
,0);
6597 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6598 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6601 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6602 SetPower( POWER_ENERGY
,0);
6604 case POWER_HAPPINESS
:
6605 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6606 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6611 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6613 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6616 static uint64 guid
= 0; // prevent repeating spam same faction problem
6618 if(GetGUID() != guid
)
6620 if(GetTypeId() == TYPEID_PLAYER
)
6621 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6623 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6630 bool Unit::IsHostileTo(Unit
const* unit
) const
6632 // always non-hostile to self
6636 // always non-hostile to GM in GM mode
6637 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6640 // always hostile to enemy
6641 if(getVictim()==unit
|| unit
->getVictim()==this)
6644 // test pet/charm masters instead pers/charmeds
6645 Unit
const* testerOwner
= GetCharmerOrOwner();
6646 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6648 // always hostile to owner's enemy
6649 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6652 // always hostile to enemy owner
6653 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6656 // always hostile to owner of owner's enemy
6657 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6660 Unit
const* tester
= testerOwner
? testerOwner
: this;
6661 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6663 // always non-hostile to target with common owner, or to owner/pet
6667 // special cases (Duel, etc)
6668 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6670 Player
const* pTester
= (Player
const*)tester
;
6671 Player
const* pTarget
= (Player
const*)target
;
6674 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6678 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6682 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6686 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6690 // Green/Blue (can't attack)
6691 if(pTester
->GetTeam()==pTarget
->GetTeam())
6694 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6695 return pTester
->IsPvP() && pTarget
->IsPvP();
6698 // faction base cases
6699 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6700 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6701 if(!tester_faction
|| !target_faction
)
6704 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6707 // PvC forced reaction and reputation case
6708 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6711 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6712 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6713 return forceItr
->second
<= REP_HOSTILE
;
6715 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6716 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6717 if(raw_target_faction
->reputationListID
>=0)
6718 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6719 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6721 // CvP forced reaction and reputation case
6722 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6725 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6726 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6727 return forceItr
->second
<= REP_HOSTILE
;
6729 // apply reputation state
6730 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6731 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6732 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6735 // common faction based case (CvC,PvC,CvP)
6736 return tester_faction
->IsHostileTo(*target_faction
);
6739 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6741 // always friendly to self
6745 // always friendly to GM in GM mode
6746 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6749 // always non-friendly to enemy
6750 if(getVictim()==unit
|| unit
->getVictim()==this)
6753 // test pet/charm masters instead pers/charmeds
6754 Unit
const* testerOwner
= GetCharmerOrOwner();
6755 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6757 // always non-friendly to owner's enemy
6758 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6761 // always non-friendly to enemy owner
6762 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6765 // always non-friendly to owner of owner's enemy
6766 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6769 Unit
const* tester
= testerOwner
? testerOwner
: this;
6770 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6772 // always friendly to target with common owner, or to owner/pet
6776 // special cases (Duel)
6777 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6779 Player
const* pTester
= (Player
const*)tester
;
6780 Player
const* pTarget
= (Player
const*)target
;
6783 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6787 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6791 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6795 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6799 // Green/Blue (non-attackable)
6800 if(pTester
->GetTeam()==pTarget
->GetTeam())
6803 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6804 return !pTarget
->IsPvP();
6807 // faction base cases
6808 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6809 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6810 if(!tester_faction
|| !target_faction
)
6813 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6816 // PvC forced reaction and reputation case
6817 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6820 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6821 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6822 return forceItr
->second
>= REP_FRIENDLY
;
6824 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6825 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6826 if(raw_target_faction
->reputationListID
>=0)
6827 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6828 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6830 // CvP forced reaction and reputation case
6831 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6834 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6835 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6836 return forceItr
->second
>= REP_FRIENDLY
;
6838 // apply reputation state
6839 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6840 if(raw_tester_faction
->reputationListID
>=0 )
6841 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6844 // common faction based case (CvC,PvC,CvP)
6845 return tester_faction
->IsFriendlyTo(*target_faction
);
6848 bool Unit::IsHostileToPlayers() const
6850 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6854 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6855 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6858 return my_faction
->IsHostileToPlayers();
6861 bool Unit::IsNeutralToAll() const
6863 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6867 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6868 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6871 return my_faction
->IsNeutralToAll();
6874 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6876 if(!victim
|| victim
== this)
6879 // dead units can neither attack nor be attacked
6880 if(!isAlive() || !victim
->isAlive())
6883 // player cannot attack in mount state
6884 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6887 // nobody can attack GM in GM-mode
6888 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6890 if(((Player
*)victim
)->isGameMaster())
6895 if(((Creature
*)victim
)->IsInEvadeMode())
6899 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6900 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6901 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6905 if (m_attacking
== victim
)
6907 // switch to melee attack from ranged/magic
6908 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6910 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6911 SendAttackStart(victim
);
6920 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6923 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6924 m_attacking
= victim
;
6925 m_attacking
->_addAttacker(this);
6927 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6928 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6930 if(GetTypeId()==TYPEID_UNIT
)
6932 WorldPacket
data(SMSG_AI_REACTION
, 12);
6933 data
<< uint64(GetGUID());
6934 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6935 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6937 ((Creature
*)this)->CallAssistence();
6938 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6941 // delay offhand weapon attack to next attack time
6942 if(haveOffhandWeapon())
6943 resetAttackTimer(OFF_ATTACK
);
6946 SendAttackStart(victim
);
6951 bool Unit::AttackStop()
6956 Unit
* victim
= m_attacking
;
6958 m_attacking
->_removeAttacker(this);
6962 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6964 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6966 InterruptSpell(CURRENT_MELEE_SPELL
);
6968 if( GetTypeId()==TYPEID_UNIT
)
6970 // reset call assistance
6971 ((Creature
*)this)->SetNoCallAssistence(false);
6974 SendAttackStop(victim
);
6979 void Unit::CombatStop(bool cast
)
6981 if(cast
& IsNonMeleeSpellCasted(false))
6982 InterruptNonMeleeSpells(false);
6985 RemoveAllAttackers();
6986 if( GetTypeId()==TYPEID_PLAYER
)
6987 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6991 void Unit::CombatStopWithPets(bool cast
)
6994 if(Pet
* pet
= GetPet())
6995 pet
->CombatStop(cast
);
6996 if(Unit
* charm
= GetCharm())
6997 charm
->CombatStop(cast
);
6998 if(GetTypeId()==TYPEID_PLAYER
)
7000 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
7001 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
7002 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
7003 guardian
->CombatStop(cast
);
7007 bool Unit::isAttackingPlayer() const
7009 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
7012 Pet
* pet
= GetPet();
7013 if(pet
&& pet
->isAttackingPlayer())
7016 Unit
* charmed
= GetCharm();
7017 if(charmed
&& charmed
->isAttackingPlayer())
7020 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7024 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7025 if(totem
&& totem
->isAttackingPlayer())
7033 void Unit::RemoveAllAttackers()
7035 while (!m_attackers
.empty())
7037 AttackerSet::iterator iter
= m_attackers
.begin();
7038 if(!(*iter
)->AttackStop())
7040 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
7041 m_attackers
.erase(iter
);
7046 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7050 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7052 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7053 if(GetTypeId() == TYPEID_PLAYER
)
7055 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7056 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7058 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7059 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7060 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7061 if (spellInfo
->CasterAuraState
== flag
)
7062 CastSpell(this, itr
->first
, true, NULL
);
7069 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7071 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7072 Unit::AuraMap
& tAuras
= GetAuras();
7073 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7075 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7076 if (spellProto
->CasterAuraState
== flag
)
7078 // exceptions (applied at state but not removed at state change)
7080 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7095 Unit
*Unit::GetOwner() const
7097 uint64 ownerid
= GetOwnerGUID();
7100 return ObjectAccessor::GetUnit(*this, ownerid
);
7103 Unit
*Unit::GetCharmer() const
7105 if(uint64 charmerid
= GetCharmerGUID())
7106 return ObjectAccessor::GetUnit(*this, charmerid
);
7110 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7112 uint64 guid
= GetCharmerOrOwnerGUID();
7113 if(IS_PLAYER_GUID(guid
))
7114 return ObjectAccessor::GetPlayer(*this, guid
);
7116 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7119 Pet
* Unit::GetPet() const
7121 if(uint64 pet_guid
= GetPetGUID())
7123 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7126 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7127 const_cast<Unit
*>(this)->SetPet(0);
7133 Unit
* Unit::GetCharm() const
7135 if(uint64 charm_guid
= GetCharmGUID())
7137 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7140 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7141 const_cast<Unit
*>(this)->SetCharm(0);
7147 void Unit::SetPet(Pet
* pet
)
7149 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7151 // FIXME: hack, speed must be set only at follow
7153 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7154 pet
->SetSpeed(UnitMoveType(i
), m_speed_rate
[i
], true);
7157 void Unit::SetCharm(Unit
* pet
)
7159 SetUInt64Value(UNIT_FIELD_CHARM
, pet
? pet
->GetGUID() : 0);
7161 if(GetTypeId() == TYPEID_PLAYER
)
7162 ((Player
*)this)->m_mover
= pet
? pet
: this;
7165 void Unit::UnsummonAllTotems()
7167 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7172 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7173 if (OldTotem
&& OldTotem
->isTotem())
7174 ((Totem
*)OldTotem
)->UnSummon();
7178 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7181 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7182 data
.append(pVictim
->GetPackGUID());
7183 data
.append(GetPackGUID());
7184 data
<< uint32(SpellID
);
7185 data
<< uint32(Damage
);
7186 data
<< uint32(0); // over healing?
7187 data
<< uint8(critical
? 1 : 0);
7188 data
<< uint8(0); // unused in client?
7189 SendMessageToSet(&data
, true);
7192 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7194 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7195 data
.append(pVictim
->GetPackGUID());
7196 data
.append(GetPackGUID());
7197 data
<< uint32(SpellID
);
7198 data
<< uint32(powertype
);
7199 data
<< uint32(Damage
);
7200 SendMessageToSet(&data
, true);
7203 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7205 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7208 int32 BonusDamage
= 0;
7209 if( GetTypeId()==TYPEID_UNIT
)
7211 // Pets just add their bonus damage to their spell damage
7212 // note that their spell damage is just gain of their own auras
7213 if (((Creature
*)this)->isPet())
7215 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7217 // For totems get damage bonus from owner (statue isn't totem in fact)
7218 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7220 if(Unit
* owner
= GetOwner())
7221 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7226 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7228 // Taken/Done fixed damage bonus auras
7229 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7230 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7232 // Damage over Time spells bonus calculation
7233 float DotFactor
= 1.0f
;
7234 if(damagetype
== DOT
)
7236 int32 DotDuration
= GetSpellDuration(spellProto
);
7240 if(DotDuration
> 30000) DotDuration
= 30000;
7241 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7243 for(int j
= 0; j
< 3; j
++)
7245 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7246 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7247 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7254 if(spellProto
->EffectAmplitude
[x
] != 0)
7255 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7258 DoneAdvertisedBenefit
/= DotTicks
;
7259 TakenAdvertisedBenefit
/= DotTicks
;
7264 // Taken/Done total percent damage auras
7265 float DoneTotalMod
= 1.0f
;
7266 float TakenTotalMod
= 1.0f
;
7269 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7270 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7272 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7273 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7274 // -1 == any item class (not wand then)
7275 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7276 // 0 == any inventory type (not wand then)
7278 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7282 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7283 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7284 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7285 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7286 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7289 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7290 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7291 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7292 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7294 // .. taken pct: scripted (increases damage of * against targets *)
7295 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7296 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7298 switch((*i
)->GetModifier()->m_miscvalue
)
7301 case 4920: case 4919:
7302 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7303 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7307 // .. taken pct: dummy auras
7308 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7309 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7311 switch((*i
)->GetSpellProto()->SpellIconID
)
7315 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7317 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7319 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7320 if (mod
< (*i
)->GetModifier()->m_amount
)
7321 mod
= (*i
)->GetModifier()->m_amount
;
7322 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7327 for(int j
=0;j
<3;j
++)
7329 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7331 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7339 // Distribute Damage over multiple effects, reduce by AoE
7340 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7342 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7343 for(int j
= 0; j
< 3; ++j
)
7345 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7346 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7353 switch(spellProto
->SpellFamilyName
)
7355 case SPELLFAMILY_MAGE
:
7356 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7357 if(spellProto
->Id
==12654)
7362 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7364 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7365 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7366 TakenTotalMod
*= 3.0f
;
7368 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7369 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7371 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7372 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7374 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7375 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7378 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7381 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7385 // Arcane Missiles triggered spell
7386 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7390 // Blizzard triggered spell
7391 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7396 case SPELLFAMILY_WARLOCK
:
7398 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7400 CastingTime
= 2800; // 80% from +shadow damage
7401 DoneTotalMod
= 1.0f
;
7402 TakenTotalMod
= 1.0f
;
7405 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7407 CastingTime
= 3360; // 96% from +shadow damage
7408 DoneTotalMod
= 1.0f
;
7409 TakenTotalMod
= 1.0f
;
7411 // Soul Fire - 115% of Fire Damage
7412 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7416 // Curse of Agony - 120% of Shadow Damage
7417 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7421 // Drain Mana - 0% of Shadow Damage
7422 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7426 // Drain Soul 214.3%
7427 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7432 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7434 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7436 // Unstable Affliction - 180%
7437 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7442 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7447 case SPELLFAMILY_PALADIN
:
7448 // Consecration - 95% of Holy Damage
7449 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7454 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7455 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7457 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7458 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7460 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7461 CastingTime
= uint32(wspeed
*3500*0.102f
);
7463 CastingTime
= uint32(wspeed
*3500*0.098f
);
7465 // Judgement of Righteousness - 73%
7466 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7470 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7471 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7476 // Holy shield - 5% of Holy Damage
7477 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7481 // Blessing of Sanctuary - 0%
7482 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7486 // Seal of Righteousness trigger - already computed for parent spell
7487 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7492 case SPELLFAMILY_SHAMAN
:
7494 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7496 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7497 CastingTime
= 749; // ignore CastingTime and use as modifier
7498 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7499 CastingTime
= 280; // ignore CastingTime and use as modifier
7500 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7501 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7503 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7504 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7505 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7507 case SPELLFAMILY_PRIEST
:
7508 // Mana Burn - 0% of Shadow Damage
7509 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7513 // Mind Flay - 59% of Shadow Damage
7514 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7518 // Holy Fire - 86.71%, DoT - 16.5%
7519 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7521 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7522 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7524 // Shadowguard - 28% per charge
7525 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7529 // Touch of Weakeness - 10%
7530 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7534 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7535 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7540 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7545 case SPELLFAMILY_DRUID
:
7546 // Hurricane triggered spell
7547 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7552 case SPELLFAMILY_WARRIOR
:
7553 case SPELLFAMILY_HUNTER
:
7554 case SPELLFAMILY_ROGUE
:
7561 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7563 // Spellmod SpellDamage
7564 float SpellModSpellDamage
= 100.0f
;
7566 if(Player
* modOwner
= GetSpellModOwner())
7567 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7569 SpellModSpellDamage
/= 100.0f
;
7571 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7572 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7574 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7576 // Add flat bonus from spell damage versus
7577 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7579 // apply spellmod to Done damage
7580 if(Player
* modOwner
= GetSpellModOwner())
7581 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7583 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7585 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7586 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7588 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7591 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7593 int32 DoneAdvertisedBenefit
= 0;
7596 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7597 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7598 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7599 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7600 // -1 == any item class (not wand then)
7601 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7602 // 0 == any inventory type (not wand then)
7603 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7605 if (GetTypeId() == TYPEID_PLAYER
)
7607 // Damage bonus from stats
7608 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7609 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7611 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7613 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7614 uint8 eff
= (*i
)->GetEffIndex();
7616 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7617 Stats usedStat
= STAT_INTELLECT
;
7618 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7619 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7621 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7624 // ... and attack power
7625 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7626 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7627 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7628 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7631 return DoneAdvertisedBenefit
;
7634 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7636 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7638 int32 TakenAdvertisedBenefit
= 0;
7639 // ..done (for creature type by mask) in taken
7640 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7641 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7642 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7643 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7646 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7647 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7648 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7649 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7651 return TakenAdvertisedBenefit
;
7654 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7656 // not critting spell
7657 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7660 float crit_chance
= 0.0f
;
7661 switch(spellProto
->DmgClass
)
7663 case SPELL_DAMAGE_CLASS_NONE
:
7665 case SPELL_DAMAGE_CLASS_MAGIC
:
7667 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7669 // For other schools
7670 else if (GetTypeId() == TYPEID_PLAYER
)
7671 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7674 crit_chance
= m_baseSpellCritChance
;
7675 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7678 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7680 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7681 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7682 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7683 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7684 // Modify by player victim resilience
7685 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7686 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7687 // scripted (increase crit chance ... against ... target by x%
7688 if(pVictim
->isFrozen()) // Shatter
7690 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7691 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7693 switch((*i
)->GetModifier()->m_miscvalue
)
7695 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7696 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7697 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7698 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7699 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7706 case SPELL_DAMAGE_CLASS_MELEE
:
7707 case SPELL_DAMAGE_CLASS_RANGED
:
7711 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7712 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7713 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7721 // only players use intelligence for critical chance computations
7722 if(Player
* modOwner
= GetSpellModOwner())
7723 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7725 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7726 if (roll_chance_f(crit_chance
))
7731 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7733 // Calculate critical bonus
7735 switch(spellProto
->DmgClass
)
7737 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7738 case SPELL_DAMAGE_CLASS_RANGED
:
7739 // TODO: write here full calculation for melee/ranged spells
7740 crit_bonus
= damage
;
7743 crit_bonus
= damage
/ 2; // for spells is 50%
7747 // adds additional damage to crit_bonus (from talents)
7748 if(Player
* modOwner
= GetSpellModOwner())
7749 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7753 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7754 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7758 damage
+= crit_bonus
;
7763 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7765 // For totems get healing bonus from owner (statue isn't totem in fact)
7766 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7767 if(Unit
* owner
= GetOwner())
7768 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7772 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7773 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7774 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7775 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7778 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7779 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7782 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7784 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7785 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7787 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7788 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7790 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7793 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7794 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7796 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7797 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7802 float ActualBenefit
= 0.0f
;
7804 if (AdvertisedBenefit
!= 0)
7806 // Healing over Time spells
7807 float DotFactor
= 1.0f
;
7808 if(damagetype
== DOT
)
7810 int32 DotDuration
= GetSpellDuration(spellProto
);
7814 if(DotDuration
> 30000) DotDuration
= 30000;
7815 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7817 for(int j
= 0; j
< 3; j
++)
7819 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7820 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7821 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7828 if(spellProto
->EffectAmplitude
[x
] != 0)
7829 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7831 AdvertisedBenefit
/= DotTicks
;
7835 // distribute healing to all effects, reduce AoE damage
7836 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7838 // 0% bonus for damage and healing spells for leech spells from healing bonus
7839 for(int j
= 0; j
< 3; ++j
)
7841 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7842 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7850 switch (spellProto
->SpellFamilyName
)
7852 case SPELLFAMILY_SHAMAN
:
7853 // Healing stream from totem (add 6% per tick from hill bonus owner)
7854 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7856 // Earth Shield 30% per charge
7857 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7860 case SPELLFAMILY_DRUID
:
7862 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7864 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7865 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7867 // Tranquility triggered spell
7868 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7871 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7874 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7876 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7877 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7880 case SPELLFAMILY_PRIEST
:
7882 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7885 case SPELLFAMILY_PALADIN
:
7886 // Seal and Judgement of Light
7887 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7890 case SPELLFAMILY_WARRIOR
:
7891 case SPELLFAMILY_ROGUE
:
7892 case SPELLFAMILY_HUNTER
:
7897 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7899 // Spellmod SpellDamage
7900 float SpellModSpellDamage
= 100.0f
;
7902 if(Player
* modOwner
= GetSpellModOwner())
7903 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7905 SpellModSpellDamage
/= 100.0f
;
7907 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7910 // use float as more appropriate for negative values and percent applying
7911 float heal
= healamount
+ ActualBenefit
;
7913 // TODO: check for ALL/SPELLS type
7914 // Healing done percent
7915 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7916 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7917 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7919 // apply spellmod to Done amount
7920 if(Player
* modOwner
= GetSpellModOwner())
7921 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7923 // Healing Wave cast
7924 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7926 // Search for Healing Way on Victim (stack up to 3 time)
7928 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7929 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7930 if((*itr
)->GetId() == 29203)
7931 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7934 heal
= heal
* (100 + pctMod
) / 100;
7937 // Healing taken percent
7938 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7940 heal
*= (100.0f
+ minval
) / 100.0f
;
7942 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7944 heal
*= (100.0f
+ maxval
) / 100.0f
;
7946 if (heal
< 0) heal
= 0;
7948 return uint32(heal
);
7951 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7953 int32 AdvertisedBenefit
= 0;
7955 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7956 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7957 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7958 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7960 // Healing bonus of spirit, intellect and strength
7961 if (GetTypeId() == TYPEID_PLAYER
)
7963 // Healing bonus from stats
7964 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7965 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7967 // stat used dependent from misc value (stat index)
7968 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7969 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7972 // ... and attack power
7973 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7974 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7975 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7976 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7978 return AdvertisedBenefit
;
7981 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7983 int32 AdvertisedBenefit
= 0;
7984 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7985 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7986 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7987 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7988 return AdvertisedBenefit
;
7991 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7993 // no charges dependent checks
7994 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7995 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7996 if(itr
->type
& shoolMask
)
7999 // charges dependent checks
8000 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
8001 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
8003 if(itr
->type
& shoolMask
)
8007 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
8008 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
8010 if((*auraItr
)->GetId()==itr
->spellId
)
8012 if((*auraItr
)->m_procCharges
> 0)
8014 --(*auraItr
)->m_procCharges
;
8015 if((*auraItr
)->m_procCharges
==0)
8016 RemoveAurasDueToSpell(itr
->spellId
);
8029 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8036 //FIX ME this hack: don't get feared if stunned
8037 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8039 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8043 // not have spells with charges currently
8044 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8045 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8046 if(itr
->type
== spellInfo
->Dispel
)
8049 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8051 // not have spells with charges currently
8052 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8053 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8054 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8055 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8059 // charges dependent checks
8061 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8062 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8064 if(itr
->type
== spellInfo
->Mechanic
)
8068 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8069 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8071 if((*auraItr
)->GetId()==itr
->spellId
)
8073 if((*auraItr
)->m_procCharges
> 0)
8075 --(*auraItr
)->m_procCharges
;
8076 if((*auraItr
)->m_procCharges
==0)
8077 RemoveAurasDueToSpell(itr
->spellId
);
8090 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8092 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8093 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8094 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8095 if(itr
->type
== effect
)
8098 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8099 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8100 if(itr
->type
== mechanic
)
8106 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8111 uint32 family
= spellInfo
->SpellFamilyName
;
8112 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8114 if((family
== 5 && flags
== 256) || //Searing Pain
8115 (family
== 6 && flags
== 8192) || //Mind Blast
8116 (family
== 11 && flags
== 1048576)) //Earth Shock
8122 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8130 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8132 // Taken/Done fixed damage bonus auras
8133 int32 DoneFlatBenefit
= 0;
8134 int32 TakenFlatBenefit
= 0;
8136 // ..done (for creature type by mask) in taken
8137 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8138 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8139 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8140 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8143 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8145 // ..done (base at attack power for marked target and base at attack power for creature type)
8147 if(attType
== RANGED_ATTACK
)
8149 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8151 // ..done (base at attack power and creature type)
8152 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8153 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8154 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8155 APbonus
+= (*i
)->GetModifier()->m_amount
;
8159 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8161 // ..done (base at attack power and creature type)
8162 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8163 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8164 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8165 APbonus
+= (*i
)->GetModifier()->m_amount
;
8168 if (APbonus
!=0) // Can be negative
8170 bool normalized
= false;
8173 for (uint8 i
= 0; i
<3;i
++)
8175 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8183 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8187 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8188 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8189 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8190 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8192 if(attType
!=RANGED_ATTACK
)
8193 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8195 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8197 // Done/Taken total percent damage auras
8198 float DoneTotalMod
= 1;
8199 float TakenTotalMod
= 1;
8202 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8203 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8205 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8206 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8207 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8208 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8211 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8212 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8213 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8214 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8216 // .. taken pct: dummy auras
8217 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8218 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8220 switch((*i
)->GetSpellProto()->SpellIconID
)
8224 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8226 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8228 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8229 if (mod
< (*i
)->GetModifier()->m_amount
)
8230 mod
= (*i
)->GetModifier()->m_amount
;
8231 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8236 if(spellProto
==NULL
)
8238 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8239 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8240 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8245 // .. taken pct: class scripts
8246 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8247 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8249 switch((*i
)->GetMiscValue())
8251 case 6427: case 6428: // Dirty Deeds
8252 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8254 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8255 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8257 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8261 // effect 0 have expected value but in negative state
8262 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8268 if(attType
!= RANGED_ATTACK
)
8270 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8271 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8272 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8276 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8277 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8278 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8281 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8283 // apply spellmod to Done damage
8286 if(Player
* modOwner
= GetSpellModOwner())
8287 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8290 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8292 // bonus result can be negative
8293 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8296 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8300 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8303 if(itr
->type
== type
)
8305 m_spellImmune
[op
].erase(itr
);
8306 next
= m_spellImmune
[op
].begin();
8310 Immune
.spellId
= spellId
;
8312 m_spellImmune
[op
].push_back(Immune
);
8316 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8318 if(itr
->spellId
== spellId
)
8320 m_spellImmune
[op
].erase(itr
);
8328 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8330 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8332 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8333 RemoveAurasWithDispelType(type
);
8336 float Unit::GetWeaponProcChance() const
8338 // normalized proc chance for weapon attack speed
8340 if(isAttackReady(BASE_ATTACK
))
8341 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8342 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8343 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8347 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8349 // proc per minute chance calculation
8350 if (PPM
<= 0) return 0.0f
;
8351 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8355 void Unit::Mount(uint32 mount
)
8360 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8362 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8364 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8367 if(GetTypeId() == TYPEID_PLAYER
)
8369 Pet
* pet
= GetPet();
8372 if(pet
->isControlled())
8374 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8375 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8378 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8381 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8385 void Unit::Unmount()
8390 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8392 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8393 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8395 // only resummon old pet if the player is already added to a map
8396 // this prevents adding a pet to a not created map which would otherwise cause a crash
8397 // (it could probably happen when logging in after a previous crash)
8398 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8400 Pet
* NewPet
= new Pet
;
8401 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8404 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8408 void Unit::SetInCombatWith(Unit
* enemy
)
8410 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8413 SetInCombatState(true);
8418 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8420 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8421 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8423 SetInCombatState(true);
8427 SetInCombatState(false);
8430 void Unit::SetInCombatState(bool PvP
)
8432 // only alive units can be in combat
8437 m_CombatTimer
= 5000;
8438 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8440 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8441 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8444 void Unit::ClearInCombat()
8447 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8449 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8450 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8452 // Player's state will be cleared in Player::UpdateContestedPvP
8453 if(GetTypeId()!=TYPEID_PLAYER
)
8454 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8457 bool Unit::isTargetableForAttack() const
8459 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8462 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8465 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8468 int32
Unit::ModifyHealth(int32 dVal
)
8475 int32 curHealth
= (int32
)GetHealth();
8477 int32 val
= dVal
+ curHealth
;
8484 int32 maxHealth
= (int32
)GetMaxHealth();
8489 gain
= val
- curHealth
;
8491 else if(curHealth
!= maxHealth
)
8493 SetHealth(maxHealth
);
8494 gain
= maxHealth
- curHealth
;
8500 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8507 int32 curPower
= (int32
)GetPower(power
);
8509 int32 val
= dVal
+ curPower
;
8516 int32 maxPower
= (int32
)GetMaxPower(power
);
8520 SetPower(power
,val
);
8521 gain
= val
- curPower
;
8523 else if(curPower
!= maxPower
)
8525 SetPower(power
,maxPower
);
8526 gain
= maxPower
- curPower
;
8532 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8537 // Always can see self
8541 // player visible for other player if not logout and at same transport
8542 // including case when player is out of world
8543 bool at_same_transport
=
8544 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8545 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8546 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8547 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8550 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8553 // forbidden to seen (at GM respawn command)
8554 if(m_Visibility
==VISIBILITY_RESPAWN
)
8557 // always seen by owner
8558 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8561 // Grid dead/alive checks
8562 if( u
->GetTypeId()==TYPEID_PLAYER
)
8564 // non visible at grid for any stealth state
8565 if(!IsVisibleInGridForPlayer((Player
*)u
))
8568 // if player is dead then he can't detect anyone in any cases
8574 // all dead creatures/players not visible for any creatures
8575 if(!u
->isAlive() || !isAlive())
8579 // different visible distance checks
8580 if(u
->isInFlight()) // what see player in flight
8582 // use object grey distance for all (only see objects any way)
8583 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8586 else if(!isAlive()) // distance for show body
8588 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8591 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8593 if(u
->GetTypeId()==TYPEID_PLAYER
)
8595 // Players far than max visible distance for player or not in our map are not visible too
8596 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8601 // Units far than max visible distance for creature or not in our map are not visible too
8602 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8606 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8608 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8609 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8612 else // distance for show creature
8614 // Units far than max visible distance for creature or not in our map are not visible too
8615 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8619 // Visible units, always are visible for all units, except for units under invisibility
8620 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8623 // GMs see any players, not higher GMs and all units
8624 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8626 if(GetTypeId() == TYPEID_PLAYER
)
8627 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8632 // non faction visibility non-breakable for non-GMs
8633 if (m_Visibility
== VISIBILITY_OFF
)
8637 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8639 // detectable invisibility case
8641 // Invisible units, always are visible for units under same invisibility type
8642 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8643 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8644 u
->canDetectInvisibilityOf(this) ||
8645 // Units that can detect invisibility always are visible for units that can be detected
8646 canDetectInvisibilityOf(u
) ))
8651 // special cases for always overwrite invisibility/stealth
8652 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8655 if (!u
->IsHostileTo(this))
8657 // 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)
8658 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8660 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8663 // else apply same rules as for hostile case (detecting check for stealth)
8669 // Hunter mark functionality
8670 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8671 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8672 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8675 // else apply detecting check for stealth
8678 // none other cases for detect invisibility, so invisible
8682 // else apply stealth detecting check
8685 // unit got in stealth in this moment and must ignore old detected state
8686 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8689 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8690 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8693 // NOW ONLY STEALTH CASE
8695 // stealth and detected and visible for some seconds
8696 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8699 //if in non-detect mode then invisible for unit
8705 // If is attacked then stealth is lost, some creature can use stealth too
8706 if( !getAttackers().empty() )
8709 // If there is collision rogue is seen regardless of level difference
8710 // TODO: check sizes in DB
8711 float distance
= GetDistance(u
);
8712 if (distance
< 0.24f
)
8715 //If a mob or player is stunned he will not be able to detect stealth
8716 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8719 // Creature can detect target only in aggro radius
8720 if(u
->GetTypeId() != TYPEID_PLAYER
)
8722 //Always invisible from back and out of aggro range
8723 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8729 //Always invisible from back
8730 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8735 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8736 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8738 //Calculation if target is in front
8740 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8741 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8743 //Visible distance is modified by
8744 //-Level Diff (every level diff = 1.0f in visible distance)
8745 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8747 //This allows to check talent tree and will add addition stealth dependent on used points)
8748 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8752 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8753 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8754 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8756 if(distance
> visibleDistance
)
8760 // Now check is target visible with LoS
8762 u
->GetPosition(ox
,oy
,oz
);
8763 return IsWithinLOS(ox
,oy
,oz
);
8766 void Unit::SetVisibility(UnitVisibility x
)
8772 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8774 if(GetTypeId()==TYPEID_PLAYER
)
8775 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8777 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8781 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8783 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8785 for(uint32 i
= 0; i
< 10; ++i
)
8787 if(((1 << i
) & mask
)==0)
8790 // find invisibility level
8791 uint32 invLevel
= 0;
8792 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8793 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8794 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8795 invLevel
= (*itr
)->GetModifier()->m_amount
;
8797 // find invisibility detect level
8798 uint32 detectLevel
= 0;
8799 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8800 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8801 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8802 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8804 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8806 detectLevel
= ((Player
*)this)->GetDrunkValue();
8809 if(invLevel
<= detectLevel
)
8817 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8819 int32 main_speed_mod
= 0;
8820 float stack_bonus
= 1.0f
;
8821 float non_stack_bonus
= 1.0f
;
8829 if (IsMounted()) // Use on mount auras
8831 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8832 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8833 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8837 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8838 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8839 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8847 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8854 if (IsMounted()) // Use on mount auras
8855 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8856 else // Use not mount (shapeshift for example) auras (should stack)
8857 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8858 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8859 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8865 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8869 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8870 // now we ready for speed calculation
8871 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8879 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8880 // TODO: possible affect only on MOVE_RUN
8881 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8883 // Use speed from aura
8884 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8885 if (speed
> max_speed
)
8894 // Apply strongest slow aura mod to speed
8895 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8897 speed
*=(100.0f
+ slow
)/100.0f
;
8898 SetSpeed(mtype
, speed
, forced
);
8901 float Unit::GetSpeed( UnitMoveType mtype
) const
8903 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8906 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8911 // Update speed only on change
8912 if (m_speed_rate
[mtype
] == rate
)
8915 m_speed_rate
[mtype
] = rate
;
8917 propagateSpeedChange();
8919 // Send speed change packet only for player
8920 if (GetTypeId()!=TYPEID_PLAYER
)
8929 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8932 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8935 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8938 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8941 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8944 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8947 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8950 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8953 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8957 data
.append(GetPackGUID());
8958 data
<< uint32(0); //movement flags
8959 data
<< uint16(0); //unk
8960 data
<< uint32(getMSTime());
8961 data
<< float(GetPositionX());
8962 data
<< float(GetPositionY());
8963 data
<< float(GetPositionZ());
8964 data
<< float(GetOrientation());
8965 data
<< uint32(0); //flag unk
8966 data
<< float(GetSpeed(mtype
));
8967 SendMessageToSet( &data
, true );
8971 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8972 // and do it only for real sent packets and use run for run/mounted as client expected
8973 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8977 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8980 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8983 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8986 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8989 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8992 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8995 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8998 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
9001 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
9004 data
.append(GetPackGUID());
9006 if (mtype
== MOVE_RUN
)
9007 data
<< uint8(0); // new 2.1.0
9008 data
<< float(GetSpeed(mtype
));
9009 SendMessageToSet( &data
, true );
9011 if(Pet
* pet
= GetPet())
9012 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9015 void Unit::SetHover(bool on
)
9018 CastSpell(this,11010,true);
9020 RemoveAurasDueToSpell(11010);
9023 void Unit::setDeathState(DeathState s
)
9025 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9029 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9031 if(IsNonMeleeSpellCasted(false))
9032 InterruptNonMeleeSpells(false);
9037 RemoveAllAurasOnDeath();
9038 UnsummonAllTotems();
9040 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9041 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9042 // remove aurastates allowing special moves
9043 ClearAllReactives();
9044 ClearDiminishings();
9046 else if(s
== JUST_ALIVED
)
9048 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9051 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9053 //_ApplyAllAuraMods();
9058 /*########################################
9060 ######## AGGRO SYSTEM ########
9062 ########################################*/
9063 bool Unit::CanHaveThreatList() const
9065 // only creatures can have threat list
9066 if( GetTypeId() != TYPEID_UNIT
)
9069 // only alive units can have threat list
9073 // pets and totems can not have threat list
9074 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() || ((Creature
*)this)->isVehicle() )
9080 //======================================================================
9082 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9084 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9087 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9089 return threat
* m_threatModifier
[school
];
9092 //======================================================================
9094 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9096 // Only mobs can manage threat lists
9097 if(CanHaveThreatList())
9098 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9101 //======================================================================
9103 void Unit::DeleteThreatList()
9105 m_ThreatManager
.clearReferences();
9108 //======================================================================
9110 void Unit::TauntApply(Unit
* taunter
)
9112 assert(GetTypeId()== TYPEID_UNIT
);
9114 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9117 if(!CanHaveThreatList())
9120 Unit
*target
= getVictim();
9121 if(target
&& target
== taunter
)
9124 SetInFront(taunter
);
9125 if (((Creature
*)this)->AI())
9126 ((Creature
*)this)->AI()->AttackStart(taunter
);
9128 m_ThreatManager
.tauntApply(taunter
);
9131 //======================================================================
9133 void Unit::TauntFadeOut(Unit
*taunter
)
9135 assert(GetTypeId()== TYPEID_UNIT
);
9137 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9140 if(!CanHaveThreatList())
9143 Unit
*target
= getVictim();
9144 if(!target
|| target
!= taunter
)
9147 if(m_ThreatManager
.isThreatListEmpty())
9149 if(((Creature
*)this)->AI())
9150 ((Creature
*)this)->AI()->EnterEvadeMode();
9154 m_ThreatManager
.tauntFadeOut(taunter
);
9155 target
= m_ThreatManager
.getHostilTarget();
9157 if (target
&& target
!= taunter
)
9160 if (((Creature
*)this)->AI())
9161 ((Creature
*)this)->AI()->AttackStart(target
);
9165 //======================================================================
9167 bool Unit::SelectHostilTarget()
9169 //function provides main threat functionality
9170 //next-victim-selection algorithm and evade mode are called
9171 //threat list sorting etc.
9173 assert(GetTypeId()== TYPEID_UNIT
);
9174 Unit
* target
= NULL
;
9176 //This function only useful once AI has been initialized
9177 if (!((Creature
*)this)->AI())
9180 if(!m_ThreatManager
.isThreatListEmpty())
9182 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9184 target
= m_ThreatManager
.getHostilTarget();
9190 if(!hasUnitState(UNIT_STAT_STUNNED
))
9192 ((Creature
*)this)->AI()->AttackStart(target
);
9196 // no target but something prevent go to evade mode
9197 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9200 // last case when creature don't must go to evade mode:
9201 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9202 // for example at owner command to pet attack some far away creature
9203 // Note: creature not have targeted movement generator but have attacker in this case
9204 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9206 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9208 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9213 // enter in evade mode in other case
9214 ((Creature
*)this)->AI()->EnterEvadeMode();
9219 //======================================================================
9220 //======================================================================
9221 //======================================================================
9223 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9225 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9227 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9229 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9230 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9231 level
= spellProto
->maxLevel
;
9233 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9234 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9235 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9236 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9237 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9239 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9240 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9241 int32 value
= basePoints
+ randvalue
;
9243 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9244 value
+= (int32
)(comboDamage
* comboPoints
);
9246 if(Player
* modOwner
= GetSpellModOwner())
9248 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9249 switch(effect_index
)
9252 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9255 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9258 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9263 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9264 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9265 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9266 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9271 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9273 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9275 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9277 int32 minduration
= GetSpellDuration(spellProto
);
9278 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9282 if( minduration
!= -1 && minduration
!= maxduration
)
9283 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9285 duration
= minduration
;
9289 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9290 // Find total mod value (negative bonus)
9291 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9292 // Find max mod (negative bonus)
9293 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9295 int32 durationMod
= 0;
9296 // Select strongest negative mod
9297 if (durationMod_always
> durationMod_not_stack
)
9298 durationMod
= durationMod_not_stack
;
9300 durationMod
= durationMod_always
;
9302 if (durationMod
!= 0)
9303 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9305 if (duration
< 0) duration
= 0;
9311 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9313 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9315 if(i
->DRGroup
!= group
)
9319 return DIMINISHING_LEVEL_1
;
9322 return DIMINISHING_LEVEL_1
;
9324 // If last spell was casted more than 15 seconds ago - reset the count.
9325 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9327 i
->hitCount
= DIMINISHING_LEVEL_1
;
9328 return DIMINISHING_LEVEL_1
;
9330 // or else increase the count.
9333 return DiminishingLevels(i
->hitCount
);
9336 return DIMINISHING_LEVEL_1
;
9339 void Unit::IncrDiminishing(DiminishingGroup group
)
9341 // Checking for existing in the table
9342 bool IsExist
= false;
9343 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9345 if(i
->DRGroup
!= group
)
9349 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9356 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9359 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9361 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9364 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9365 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9367 // test pet/charm masters instead pets/charmeds
9368 Unit
const* targetOwner
= GetCharmerOrOwner();
9369 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9371 Unit
const* target
= targetOwner
? targetOwner
: this;
9372 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9374 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9380 // Some diminishings applies to mobs too (for example, Stun)
9381 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9383 DiminishingLevels diminish
= Level
;
9386 case DIMINISHING_LEVEL_1
: break;
9387 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9388 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9389 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9394 duration
= int32(duration
* mod
);
9397 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9399 // Checking for existing in the table
9400 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9402 if(i
->DRGroup
!= group
)
9405 i
->hitTime
= getMSTime();
9416 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9418 return ObjectAccessor::GetUnit(object
,guid
);
9421 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9423 return isVisibleForOrDetect(u
,false,inVisibleList
);
9426 uint32
Unit::GetCreatureType() const
9428 if(GetTypeId() == TYPEID_PLAYER
)
9430 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9431 if(ssEntry
&& ssEntry
->creatureType
> 0)
9432 return ssEntry
->creatureType
;
9434 return CREATURE_TYPE_HUMANOID
;
9437 return ((Creature
*)this)->GetCreatureInfo()->type
;
9440 /*#######################################
9442 ######## STAT SYSTEM ########
9444 #######################################*/
9446 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9448 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9450 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9456 switch(modifierType
)
9460 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9464 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9467 val
= (100.0f
+ amount
) / 100.0f
;
9468 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9475 if(!CanModifyStats())
9480 case UNIT_MOD_STAT_STRENGTH
:
9481 case UNIT_MOD_STAT_AGILITY
:
9482 case UNIT_MOD_STAT_STAMINA
:
9483 case UNIT_MOD_STAT_INTELLECT
:
9484 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9486 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9487 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9491 case UNIT_MOD_FOCUS
:
9492 case UNIT_MOD_ENERGY
:
9493 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9495 case UNIT_MOD_RESISTANCE_HOLY
:
9496 case UNIT_MOD_RESISTANCE_FIRE
:
9497 case UNIT_MOD_RESISTANCE_NATURE
:
9498 case UNIT_MOD_RESISTANCE_FROST
:
9499 case UNIT_MOD_RESISTANCE_SHADOW
:
9500 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9502 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9503 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9505 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9506 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9507 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9516 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9518 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9520 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9524 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9527 return m_auraModifiersGroup
[unitMod
][modifierType
];
9530 float Unit::GetTotalStatValue(Stats stat
) const
9532 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9534 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9537 // value = ((base_value * base_pct) + total_value) * total_pct
9538 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9539 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9540 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9541 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9546 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9548 if(unitMod
>= UNIT_MOD_END
)
9550 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9554 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9557 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9558 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9559 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9560 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9565 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9567 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9571 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9572 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9573 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9574 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9575 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9576 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9585 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9587 Stats stat
= STAT_STRENGTH
;
9591 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9592 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9593 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9594 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9595 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9604 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9606 Powers power
= POWER_MANA
;
9610 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9611 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9612 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9613 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9614 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9623 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9625 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9627 float val
= GetTotalAuraModValue(unitMod
);
9634 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9636 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9639 return m_weaponDamage
[attType
][type
];
9642 void Unit::SetLevel(uint32 lvl
)
9644 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9647 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9648 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9651 void Unit::SetHealth(uint32 val
)
9653 uint32 maxHealth
= GetMaxHealth();
9657 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9660 if(GetTypeId() == TYPEID_PLAYER
)
9662 if(((Player
*)this)->GetGroup())
9663 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9665 else if(((Creature
*)this)->isPet())
9667 Pet
*pet
= ((Pet
*)this);
9668 if(pet
->isControlled())
9670 Unit
*owner
= GetOwner();
9671 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9672 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9677 void Unit::SetMaxHealth(uint32 val
)
9679 uint32 health
= GetHealth();
9680 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9683 if(GetTypeId() == TYPEID_PLAYER
)
9685 if(((Player
*)this)->GetGroup())
9686 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9688 else if(((Creature
*)this)->isPet())
9690 Pet
*pet
= ((Pet
*)this);
9691 if(pet
->isControlled())
9693 Unit
*owner
= GetOwner();
9694 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9695 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9703 void Unit::SetPower(Powers power
, uint32 val
)
9705 uint32 maxPower
= GetMaxPower(power
);
9709 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9711 WorldPacket
data(SMSG_POWER_UPDATE
);
9712 data
.append(GetPackGUID());
9713 data
<< uint8(power
);
9714 data
<< uint32(val
);
9715 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9718 if(GetTypeId() == TYPEID_PLAYER
)
9720 if(((Player
*)this)->GetGroup())
9721 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9723 else if(((Creature
*)this)->isPet())
9725 Pet
*pet
= ((Pet
*)this);
9726 if(pet
->isControlled())
9728 Unit
*owner
= GetOwner();
9729 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9730 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9733 // Update the pet's character sheet with happiness damage bonus
9734 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9736 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9741 void Unit::SetMaxPower(Powers power
, uint32 val
)
9743 uint32 cur_power
= GetPower(power
);
9744 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9747 if(GetTypeId() == TYPEID_PLAYER
)
9749 if(((Player
*)this)->GetGroup())
9750 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9752 else if(((Creature
*)this)->isPet())
9754 Pet
*pet
= ((Pet
*)this);
9755 if(pet
->isControlled())
9757 Unit
*owner
= GetOwner();
9758 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9759 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9764 SetPower(power
, val
);
9767 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9769 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9772 if(GetTypeId() == TYPEID_PLAYER
)
9774 if(((Player
*)this)->GetGroup())
9775 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9777 else if(((Creature
*)this)->isPet())
9779 Pet
*pet
= ((Pet
*)this);
9780 if(pet
->isControlled())
9782 Unit
*owner
= GetOwner();
9783 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9784 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9789 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9791 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9794 if(GetTypeId() == TYPEID_PLAYER
)
9796 if(((Player
*)this)->GetGroup())
9797 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9799 else if(((Creature
*)this)->isPet())
9801 Pet
*pet
= ((Pet
*)this);
9802 if(pet
->isControlled())
9804 Unit
*owner
= GetOwner();
9805 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9806 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9811 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9813 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9815 tAuraProcTriggerDamage
.push_back(aura
);
9817 tAuraProcTriggerDamage
.remove(aura
);
9820 uint32
Unit::GetCreatePowers( Powers power
) const
9822 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9825 case POWER_MANA
: return GetCreateMana();
9826 case POWER_RAGE
: return 1000;
9827 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9828 case POWER_ENERGY
: return 100;
9829 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9830 case POWER_RUNIC_POWER
: return 1000;
9836 void Unit::AddToWorld()
9838 Object::AddToWorld();
9841 void Unit::RemoveFromWorld()
9846 RemoveNotOwnSingleTargetAuras();
9849 Object::RemoveFromWorld();
9852 void Unit::CleanupsBeforeDelete()
9854 if(m_uint32Values
) // only for fully created object
9856 InterruptNonMeleeSpells(true);
9857 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9859 ClearComboPointHolders();
9861 getHostilRefManager().setOnlineOfflineState(false);
9863 RemoveAllGameObjects();
9864 RemoveAllDynObjects();
9865 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9870 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9873 m_charmInfo
= new CharmInfo(charm
);
9877 CharmInfo::CharmInfo(Unit
* unit
)
9878 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9880 for(int i
=0; i
<4; ++i
)
9882 m_charmspells
[i
].spellId
= 0;
9883 m_charmspells
[i
].active
= ACT_DISABLED
;
9887 void CharmInfo::InitPetActionBar()
9889 // the first 3 SpellOrActions are attack, follow and stay
9890 for(uint32 i
= 0; i
< 3; i
++)
9892 PetActionBar
[i
].Type
= ACT_COMMAND
;
9893 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9895 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9896 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9898 for(uint32 i
=0; i
< 4; i
++)
9900 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9901 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9905 void CharmInfo::InitEmptyActionBar()
9907 for(uint32 x
= 1; x
< 10; ++x
)
9909 PetActionBar
[x
].Type
= ACT_PASSIVE
;
9910 PetActionBar
[x
].SpellOrAction
= 0;
9912 PetActionBar
[0].Type
= ACT_COMMAND
;
9913 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9916 void CharmInfo::InitPossessCreateSpells()
9918 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9921 InitEmptyActionBar(); //charm action bar
9923 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9925 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9926 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9928 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_PASSIVE
);
9932 void CharmInfo::InitCharmCreateSpells()
9934 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9936 InitEmptyActionBar();
9942 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9944 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9945 m_charmspells
[x
].spellId
= spellId
;
9950 if (IsPassiveSpell(spellId
))
9952 m_unit
->CastSpell(m_unit
, spellId
, true);
9953 m_charmspells
[x
].active
= ACT_PASSIVE
;
9957 ActiveStates newstate
;
9958 bool onlyselfcast
= true;
9959 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9961 if(!spellInfo
) onlyselfcast
= false;
9962 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9964 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9965 onlyselfcast
= false;
9968 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9969 newstate
= ACT_DISABLED
;
9971 newstate
= ACT_PASSIVE
;
9973 AddSpellToAB(0, spellId
, newstate
);
9978 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9980 for(uint8 i
= 0; i
< 10; i
++)
9982 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_PASSIVE
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9984 PetActionBar
[i
].SpellOrAction
= newid
;
9987 if(newstate
== ACT_DECIDE
)
9988 PetActionBar
[i
].Type
= ACT_DISABLED
;
9990 PetActionBar
[i
].Type
= newstate
;
9999 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
10001 if(IsPassiveSpell(spellid
))
10004 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
10006 if(spellid
== m_charmspells
[x
].spellId
)
10008 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
10013 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10015 m_petnumber
= petnumber
;
10017 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10019 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10022 bool Unit::isFrozen() const
10024 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10025 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10026 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10031 struct ProcTriggeredData
10033 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
10034 : triggeredByAura(_triggeredByAura
),
10035 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10036 cooldown(_cooldown
)
10039 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10040 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10041 uint32 cooldown
; // possible hidden cooldown
10044 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10046 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10048 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10050 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10051 ProcTriggeredList procTriggered
;
10053 AuraList
const& auras
= GetAurasByType(*aur
);
10054 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10060 uint32 cooldown
; // returned at next line
10061 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10064 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10067 // Handle effects proceed this time
10068 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10070 // Some auras can be deleted in function called in this loop (except first, ofc)
10071 // Until storing auras in std::multimap to hard check deleting by another way
10072 if(i
!= procTriggered
.begin())
10074 bool found
= false;
10075 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10076 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10077 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10079 if(itr
->second
==i
->triggeredByAura
)
10088 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
);
10089 sLog
.outError("It can be deleted one from early processed auras:");
10090 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10091 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10092 sLog
.outError(" <end of list>");
10097 /// this is aura triggering code call
10098 Aura
* triggeredByAura
= i
->triggeredByAura
;
10100 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10101 /// used in speedup code check before check aura existance.
10102 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10104 /// success in event proccesing
10105 /// used in speedup code check before check aura existance.
10106 bool casted
= false;
10108 /// process triggered code
10111 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10113 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10114 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10115 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10118 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10120 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10121 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10122 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10123 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10127 case SPELL_AURA_DUMMY
:
10129 uint32 effect
= triggeredByAura
->GetEffIndex();
10130 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10131 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10132 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10135 case SPELL_AURA_PRAYER_OF_MENDING
:
10137 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10138 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10140 casted
= HandleMeandingAuraProc(triggeredByAura
);
10143 case SPELL_AURA_MOD_HASTE
:
10145 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10146 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10147 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10150 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10152 // nothing do, just charges counter
10153 // but count only in case appropriate school damage
10154 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10157 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10159 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10160 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10161 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10166 // nothing do, just charges counter
10172 /// Update charge (aura can be removed by triggers)
10173 if(casted
&& triggeredByAuraWithCharges
)
10175 /// need re-found aura (can be dropped by triggers)
10176 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10177 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10178 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10180 if(itr
->second
== triggeredByAura
) // pointer still valid
10182 if(triggeredByAura
->m_procCharges
> 0)
10183 triggeredByAura
->m_procCharges
-= 1;
10185 triggeredByAura
->UpdateAuraCharges();
10192 /// Safely remove auras with zero charges
10193 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10196 if((*i
)->m_procCharges
== 0)
10198 RemoveAurasDueToSpell((*i
)->GetId());
10199 next
= auras
.begin();
10205 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10207 return SPELL_SCHOOL_MASK_NORMAL
;
10210 Player
* Unit::GetSpellModOwner()
10212 if(GetTypeId()==TYPEID_PLAYER
)
10213 return (Player
*)this;
10214 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10216 Unit
* owner
= GetOwner();
10217 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10218 return (Player
*)owner
;
10223 ///----------Pet responses methods-----------------
10224 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10226 Unit
*owner
= GetCharmerOrOwner();
10227 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10230 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10231 data
<< uint8(0); // cast count?
10232 data
<< uint32(spellid
);
10233 data
<< uint8(msg
);
10234 // uint32 for some reason
10235 // uint32 for some reason
10236 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10239 void Unit::SendPetActionFeedback (uint8 msg
)
10241 Unit
* owner
= GetOwner();
10242 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10245 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10246 data
<< uint8(msg
);
10247 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10250 void Unit::SendPetTalk (uint32 pettalk
)
10252 Unit
* owner
= GetOwner();
10253 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10256 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10257 data
<< uint64(GetGUID());
10258 data
<< uint32(pettalk
);
10259 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10262 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10264 Unit
* owner
= GetOwner();
10265 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10268 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10269 data
<< uint64(GetGUID());
10270 data
<< uint8(0x0); // flags (0x1, 0x2)
10271 data
<< uint32(spellid
);
10272 data
<< uint32(cooltime
);
10274 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10277 void Unit::SendPetClearCooldown (uint32 spellid
)
10279 Unit
* owner
= GetOwner();
10280 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10283 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10284 data
<< uint32(spellid
);
10285 data
<< uint64(GetGUID());
10286 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10289 void Unit::SendPetAIReaction(uint64 guid
)
10291 Unit
* owner
= GetOwner();
10292 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10295 WorldPacket
data(SMSG_AI_REACTION
, 12);
10296 data
<< uint64(guid
) << uint32(00000002);
10297 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10300 ///----------End of Pet responses methods----------
10302 void Unit::StopMoving()
10304 clearUnitState(UNIT_STAT_MOVING
);
10306 // send explicit stop packet
10307 // rely on vmaps here because for example stormwind is in air
10308 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10309 //if (fabs(GetPositionZ() - z) < 2.0f)
10310 // Relocate(GetPositionX(), GetPositionY(), z);
10311 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10313 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10315 // update position and orientation;
10317 BuildHeartBeatMsg(&data
);
10318 SendMessageToSet(&data
,false);
10321 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10325 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10328 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10330 GetMotionMaster()->MovementExpired(false);
10331 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10333 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10335 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10339 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10341 GetMotionMaster()->MovementExpired(false);
10343 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10345 // restore appropriate movement generator
10347 GetMotionMaster()->MoveChase(getVictim());
10349 GetMotionMaster()->Initialize();
10351 // attack caster if can
10352 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10353 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10354 ((Creature
*)this)->AI()->AttackStart(caster
);
10358 if (GetTypeId() == TYPEID_PLAYER
)
10359 ((Player
*)this)->SetClientControl(this, !apply
);
10362 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10366 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10368 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10370 GetMotionMaster()->MoveConfused();
10374 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10376 GetMotionMaster()->MovementExpired(false);
10378 if (GetTypeId() == TYPEID_UNIT
)
10380 // if in combat restore movement generator
10382 GetMotionMaster()->MoveChase(getVictim());
10386 if(GetTypeId() == TYPEID_PLAYER
)
10387 ((Player
*)this)->SetClientControl(this, !apply
);
10390 bool Unit::IsSitState() const
10392 uint8 s
= getStandState();
10393 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10394 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10395 s
== PLAYER_STATE_SIT
;
10398 bool Unit::IsStandState() const
10400 uint8 s
= getStandState();
10401 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10404 void Unit::SetStandState(uint8 state
)
10406 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10408 if (IsStandState())
10409 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10411 if(GetTypeId()==TYPEID_PLAYER
)
10413 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10414 data
<< (uint8
)state
;
10415 ((Player
*)this)->GetSession()->SendPacket(&data
);
10419 bool Unit::IsPolymorphed() const
10421 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10424 void Unit::SetDisplayId(uint32 modelId
)
10426 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10428 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10430 Pet
*pet
= ((Pet
*)this);
10431 if(!pet
->isControlled())
10433 Unit
*owner
= GetOwner();
10434 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10435 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10439 void Unit::ClearComboPointHolders()
10441 while(!m_ComboPointHolders
.empty())
10443 uint32 lowguid
= *m_ComboPointHolders
.begin();
10445 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10446 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10447 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10449 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10453 void Unit::ClearAllReactives()
10456 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10457 m_reactiveTimer
[i
] = 0;
10459 if (HasAuraState( AURA_STATE_DEFENSE
))
10460 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10461 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10462 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10463 if (HasAuraState( AURA_STATE_CRIT
))
10464 ModifyAuraState(AURA_STATE_CRIT
, false);
10465 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10466 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10468 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10469 ((Player
*)this)->ClearComboPoints();
10472 void Unit::UpdateReactives( uint32 p_time
)
10474 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10476 ReactiveType reactive
= ReactiveType(i
);
10478 if(!m_reactiveTimer
[reactive
])
10481 if ( m_reactiveTimer
[reactive
] <= p_time
)
10483 m_reactiveTimer
[reactive
] = 0;
10485 switch ( reactive
)
10487 case REACTIVE_DEFENSE
:
10488 if (HasAuraState(AURA_STATE_DEFENSE
))
10489 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10491 case REACTIVE_HUNTER_PARRY
:
10492 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10493 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10495 case REACTIVE_CRIT
:
10496 if (HasAuraState(AURA_STATE_CRIT
))
10497 ModifyAuraState(AURA_STATE_CRIT
, false);
10499 case REACTIVE_HUNTER_CRIT
:
10500 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10501 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10503 case REACTIVE_OVERPOWER
:
10504 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10505 ((Player
*)this)->ClearComboPoints();
10513 m_reactiveTimer
[reactive
] -= p_time
;
10518 Unit
* Unit::SelectNearbyTarget() const
10520 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10522 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10523 cell
.SetNoCreate();
10525 std::list
<Unit
*> targets
;
10528 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10529 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10531 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10532 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10534 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10535 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10536 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10539 // remove current target
10541 targets
.remove(getVictim());
10543 // remove not LoS targets
10544 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10546 if(!IsWithinLOSInMap(*tIter
))
10548 std::list
<Unit
*>::iterator tIter2
= tIter
;
10550 targets
.erase(tIter2
);
10556 // no appropriate targets
10557 if(targets
.empty())
10561 uint32 rIdx
= urand(0,targets
.size()-1);
10562 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10563 for(uint32 i
= 0; i
< rIdx
; ++i
)
10569 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10573 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10574 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10578 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10579 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10583 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10586 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10588 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10591 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10593 if (CastingTime
> 7000) CastingTime
= 7000;
10594 if (CastingTime
< 1500) CastingTime
= 1500;
10596 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10597 CastingTime
= 3500;
10599 int32 overTime
= 0;
10601 bool DirectDamage
= false;
10602 bool AreaEffect
= false;
10604 for ( uint32 i
=0; i
<3;i
++)
10606 switch ( spellProto
->Effect
[i
] )
10608 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10609 case SPELL_EFFECT_POWER_DRAIN
:
10610 case SPELL_EFFECT_HEALTH_LEECH
:
10611 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10612 case SPELL_EFFECT_POWER_BURN
:
10613 case SPELL_EFFECT_HEAL
:
10614 DirectDamage
= true;
10616 case SPELL_EFFECT_APPLY_AURA
:
10617 switch ( spellProto
->EffectApplyAuraName
[i
] )
10619 case SPELL_AURA_PERIODIC_DAMAGE
:
10620 case SPELL_AURA_PERIODIC_HEAL
:
10621 case SPELL_AURA_PERIODIC_LEECH
:
10622 if ( GetSpellDuration(spellProto
) )
10623 overTime
= GetSpellDuration(spellProto
);
10626 // -5% per additional effect
10634 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10638 // Combined Spells with Both Over Time and Direct Damage
10639 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10641 // mainly for DoTs which are 3500 here otherwise
10642 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10643 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10644 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10645 // Portion to Over Time
10646 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10648 if ( damagetype
== DOT
)
10649 CastingTime
= uint32(CastingTime
* PtOT
);
10650 else if ( PtOT
< 1.0f
)
10651 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10656 // Area Effect Spells receive only half of bonus
10660 // -5% of total per any additional effect
10661 for ( uint8 i
=0; i
<effects
; ++i
)
10663 if ( CastingTime
> 175 )
10665 CastingTime
-= 175;
10674 return CastingTime
;
10677 void Unit::UpdateAuraForGroup(uint8 slot
)
10679 if(GetTypeId() == TYPEID_PLAYER
)
10681 Player
* player
= (Player
*)this;
10682 if(player
->GetGroup())
10684 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10685 player
->SetAuraUpdateMask(slot
);
10688 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10690 Pet
*pet
= ((Pet
*)this);
10691 if(pet
->isControlled())
10693 Unit
*owner
= GetOwner();
10694 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10696 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10697 pet
->SetAuraUpdateMask(slot
);
10703 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10705 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10706 return float(GetAttackTime(attType
))/1000.0f
;
10708 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10710 return 2.4; // fist attack
10712 switch (Weapon
->GetProto()->InventoryType
)
10714 case INVTYPE_2HWEAPON
:
10716 case INVTYPE_RANGED
:
10717 case INVTYPE_RANGEDRIGHT
:
10718 case INVTYPE_THROWN
:
10720 case INVTYPE_WEAPON
:
10721 case INVTYPE_WEAPONMAINHAND
:
10722 case INVTYPE_WEAPONOFFHAND
:
10724 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10728 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10730 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10731 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10732 if ((*itr
)->GetId() == spell_id
)
10738 bool Unit::IsUnderLastManaUseEffect() const
10740 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10743 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10745 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10747 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10750 player
->SetContestedPvPTimer(30000);
10751 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10753 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10754 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10755 // call MoveInLineOfSight for nearby contested guards
10756 SetVisibility(GetVisibility());
10758 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10760 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10761 // call MoveInLineOfSight for nearby contested guards
10762 SetVisibility(GetVisibility());
10766 void Unit::AddPetAura(PetAura
const* petSpell
)
10768 m_petAuras
.insert(petSpell
);
10769 if(Pet
* pet
= GetPet())
10770 pet
->CastPetAura(petSpell
);
10773 void Unit::RemovePetAura(PetAura
const* petSpell
)
10775 m_petAuras
.erase(petSpell
);
10776 if(Pet
* pet
= GetPet())
10777 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10780 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10782 Pet
* pet
= new Pet(HUNTER_PET
);
10784 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10790 pet
->SetOwnerGUID(GetGUID());
10791 pet
->SetCreatorGUID(GetGUID());
10792 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, getFaction());
10793 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10795 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10796 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10798 if(!pet
->InitStatsForLevel(level
))
10800 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10805 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10806 // this enables pet details window (Shift+P)
10807 pet
->AIM_Initialize();
10808 pet
->InitPetCreateSpells();
10809 pet
->SetHealth(pet
->GetMaxHealth());
10814 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10816 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10818 if(!spellProcEvent
)
10820 // used to prevent spam in log about same non-handled spells
10821 static std::set
<uint32
> nonHandledSpellProcSet
;
10823 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10825 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10826 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10829 // spell.dbc use totally different flags, that only can create problems if used.
10833 // Check spellProcEvent data requirements
10834 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10837 // Check if current equipment allows aura to proc
10838 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10840 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10842 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10844 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10847 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10849 // Check if player is wearing shield
10850 Item
*item
= ((Player
*)this)->GetShield(true);
10851 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10856 float chance
= (float)spellProto
->procChance
;
10858 if(Player
* modOwner
= GetSpellModOwner())
10859 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10861 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10863 uint32 WeaponSpeed
= GetAttackTime(attType
);
10864 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10867 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10868 return roll_chance_f(chance
);
10871 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10873 // aura can be deleted at casts
10874 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10875 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10876 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10877 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10880 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10882 // current aura expire
10883 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10885 // next target selection
10886 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10889 if (spellProto
->EffectRadiusIndex
[effIdx
])
10890 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10892 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10894 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10896 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10898 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10900 // aura will applied from caster, but spell casted from current aura holder
10901 SpellModifier
*mod
= new SpellModifier
;
10902 mod
->op
= SPELLMOD_CHARGES
;
10903 mod
->value
= jumps
-5; // negative
10904 mod
->type
= SPELLMOD_FLAT
;
10905 mod
->spellId
= spellProto
->Id
;
10906 mod
->effectId
= effIdx
;
10907 mod
->lastAffected
= NULL
;
10908 mod
->mask
= spellProto
->SpellFamilyFlags
;
10911 caster
->AddSpellMod(mod
, true);
10912 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10913 caster
->AddSpellMod(mod
, false);
10919 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);