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
* charmed
)
7159 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7162 void Unit::UnsummonAllTotems()
7164 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7169 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7170 if (OldTotem
&& OldTotem
->isTotem())
7171 ((Totem
*)OldTotem
)->UnSummon();
7175 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7178 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7179 data
.append(pVictim
->GetPackGUID());
7180 data
.append(GetPackGUID());
7181 data
<< uint32(SpellID
);
7182 data
<< uint32(Damage
);
7183 data
<< uint32(0); // over healing?
7184 data
<< uint8(critical
? 1 : 0);
7185 data
<< uint8(0); // unused in client?
7186 SendMessageToSet(&data
, true);
7189 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7191 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7192 data
.append(pVictim
->GetPackGUID());
7193 data
.append(GetPackGUID());
7194 data
<< uint32(SpellID
);
7195 data
<< uint32(powertype
);
7196 data
<< uint32(Damage
);
7197 SendMessageToSet(&data
, true);
7200 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7202 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7205 int32 BonusDamage
= 0;
7206 if( GetTypeId()==TYPEID_UNIT
)
7208 // Pets just add their bonus damage to their spell damage
7209 // note that their spell damage is just gain of their own auras
7210 if (((Creature
*)this)->isPet())
7212 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7214 // For totems get damage bonus from owner (statue isn't totem in fact)
7215 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7217 if(Unit
* owner
= GetOwner())
7218 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7223 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7225 // Taken/Done fixed damage bonus auras
7226 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7227 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7229 // Damage over Time spells bonus calculation
7230 float DotFactor
= 1.0f
;
7231 if(damagetype
== DOT
)
7233 int32 DotDuration
= GetSpellDuration(spellProto
);
7237 if(DotDuration
> 30000) DotDuration
= 30000;
7238 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7240 for(int j
= 0; j
< 3; j
++)
7242 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7243 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7244 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7251 if(spellProto
->EffectAmplitude
[x
] != 0)
7252 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7255 DoneAdvertisedBenefit
/= DotTicks
;
7256 TakenAdvertisedBenefit
/= DotTicks
;
7261 // Taken/Done total percent damage auras
7262 float DoneTotalMod
= 1.0f
;
7263 float TakenTotalMod
= 1.0f
;
7266 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7267 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7269 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7270 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7271 // -1 == any item class (not wand then)
7272 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7273 // 0 == any inventory type (not wand then)
7275 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7279 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7280 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7281 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7282 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7283 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7286 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7287 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7288 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7289 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7291 // .. taken pct: scripted (increases damage of * against targets *)
7292 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7293 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7295 switch((*i
)->GetModifier()->m_miscvalue
)
7298 case 4920: case 4919:
7299 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7300 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7304 // .. taken pct: dummy auras
7305 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7306 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7308 switch((*i
)->GetSpellProto()->SpellIconID
)
7312 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7314 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7316 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7317 if (mod
< (*i
)->GetModifier()->m_amount
)
7318 mod
= (*i
)->GetModifier()->m_amount
;
7319 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7324 for(int j
=0;j
<3;j
++)
7326 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7328 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7336 // Distribute Damage over multiple effects, reduce by AoE
7337 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7339 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7340 for(int j
= 0; j
< 3; ++j
)
7342 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7343 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7350 switch(spellProto
->SpellFamilyName
)
7352 case SPELLFAMILY_MAGE
:
7353 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7354 if(spellProto
->Id
==12654)
7359 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7361 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7362 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7363 TakenTotalMod
*= 3.0f
;
7365 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7366 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7368 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7369 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7371 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7372 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7375 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7378 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7382 // Arcane Missiles triggered spell
7383 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7387 // Blizzard triggered spell
7388 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7393 case SPELLFAMILY_WARLOCK
:
7395 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7397 CastingTime
= 2800; // 80% from +shadow damage
7398 DoneTotalMod
= 1.0f
;
7399 TakenTotalMod
= 1.0f
;
7402 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7404 CastingTime
= 3360; // 96% from +shadow damage
7405 DoneTotalMod
= 1.0f
;
7406 TakenTotalMod
= 1.0f
;
7408 // Soul Fire - 115% of Fire Damage
7409 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7413 // Curse of Agony - 120% of Shadow Damage
7414 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7418 // Drain Mana - 0% of Shadow Damage
7419 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7423 // Drain Soul 214.3%
7424 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7429 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7431 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7433 // Unstable Affliction - 180%
7434 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7439 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7444 case SPELLFAMILY_PALADIN
:
7445 // Consecration - 95% of Holy Damage
7446 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7451 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7452 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7454 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7455 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7457 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7458 CastingTime
= uint32(wspeed
*3500*0.102f
);
7460 CastingTime
= uint32(wspeed
*3500*0.098f
);
7462 // Judgement of Righteousness - 73%
7463 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7467 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7468 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7473 // Holy shield - 5% of Holy Damage
7474 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7478 // Blessing of Sanctuary - 0%
7479 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7483 // Seal of Righteousness trigger - already computed for parent spell
7484 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7489 case SPELLFAMILY_SHAMAN
:
7491 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7493 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7494 CastingTime
= 749; // ignore CastingTime and use as modifier
7495 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7496 CastingTime
= 280; // ignore CastingTime and use as modifier
7497 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7498 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7500 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7501 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7502 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7504 case SPELLFAMILY_PRIEST
:
7505 // Mana Burn - 0% of Shadow Damage
7506 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7510 // Mind Flay - 59% of Shadow Damage
7511 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7515 // Holy Fire - 86.71%, DoT - 16.5%
7516 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7518 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7519 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7521 // Shadowguard - 28% per charge
7522 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7526 // Touch of Weakeness - 10%
7527 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7531 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7532 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7537 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7542 case SPELLFAMILY_DRUID
:
7543 // Hurricane triggered spell
7544 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7549 case SPELLFAMILY_WARRIOR
:
7550 case SPELLFAMILY_HUNTER
:
7551 case SPELLFAMILY_ROGUE
:
7558 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7560 // Spellmod SpellDamage
7561 float SpellModSpellDamage
= 100.0f
;
7563 if(Player
* modOwner
= GetSpellModOwner())
7564 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7566 SpellModSpellDamage
/= 100.0f
;
7568 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7569 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7571 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7573 // Add flat bonus from spell damage versus
7574 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7576 // apply spellmod to Done damage
7577 if(Player
* modOwner
= GetSpellModOwner())
7578 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7580 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7582 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7583 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7585 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7588 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7590 int32 DoneAdvertisedBenefit
= 0;
7593 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7594 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7595 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7596 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7597 // -1 == any item class (not wand then)
7598 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7599 // 0 == any inventory type (not wand then)
7600 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7602 if (GetTypeId() == TYPEID_PLAYER
)
7604 // Damage bonus from stats
7605 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7606 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7608 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7610 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7611 uint8 eff
= (*i
)->GetEffIndex();
7613 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7614 Stats usedStat
= STAT_INTELLECT
;
7615 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7616 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7618 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7621 // ... and attack power
7622 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7623 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7624 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7625 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7628 return DoneAdvertisedBenefit
;
7631 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7633 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7635 int32 TakenAdvertisedBenefit
= 0;
7636 // ..done (for creature type by mask) in taken
7637 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7638 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7639 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7640 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7643 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7644 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7645 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7646 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7648 return TakenAdvertisedBenefit
;
7651 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7653 // not critting spell
7654 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7657 float crit_chance
= 0.0f
;
7658 switch(spellProto
->DmgClass
)
7660 case SPELL_DAMAGE_CLASS_NONE
:
7662 case SPELL_DAMAGE_CLASS_MAGIC
:
7664 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7666 // For other schools
7667 else if (GetTypeId() == TYPEID_PLAYER
)
7668 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7671 crit_chance
= m_baseSpellCritChance
;
7672 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7675 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7677 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7678 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7679 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7680 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7681 // Modify by player victim resilience
7682 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7683 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7684 // scripted (increase crit chance ... against ... target by x%
7685 if(pVictim
->isFrozen()) // Shatter
7687 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7688 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7690 switch((*i
)->GetModifier()->m_miscvalue
)
7692 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7693 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7694 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7695 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7696 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7703 case SPELL_DAMAGE_CLASS_MELEE
:
7704 case SPELL_DAMAGE_CLASS_RANGED
:
7708 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7709 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7710 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7718 // only players use intelligence for critical chance computations
7719 if(Player
* modOwner
= GetSpellModOwner())
7720 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7722 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7723 if (roll_chance_f(crit_chance
))
7728 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7730 // Calculate critical bonus
7732 switch(spellProto
->DmgClass
)
7734 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7735 case SPELL_DAMAGE_CLASS_RANGED
:
7736 // TODO: write here full calculation for melee/ranged spells
7737 crit_bonus
= damage
;
7740 crit_bonus
= damage
/ 2; // for spells is 50%
7744 // adds additional damage to crit_bonus (from talents)
7745 if(Player
* modOwner
= GetSpellModOwner())
7746 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7750 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7751 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7755 damage
+= crit_bonus
;
7760 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7762 // For totems get healing bonus from owner (statue isn't totem in fact)
7763 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7764 if(Unit
* owner
= GetOwner())
7765 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7769 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7770 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7771 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7772 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7775 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7776 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7779 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7781 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7782 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7784 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7785 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7787 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7790 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7791 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7793 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7794 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7799 float ActualBenefit
= 0.0f
;
7801 if (AdvertisedBenefit
!= 0)
7803 // Healing over Time spells
7804 float DotFactor
= 1.0f
;
7805 if(damagetype
== DOT
)
7807 int32 DotDuration
= GetSpellDuration(spellProto
);
7811 if(DotDuration
> 30000) DotDuration
= 30000;
7812 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7814 for(int j
= 0; j
< 3; j
++)
7816 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7817 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7818 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7825 if(spellProto
->EffectAmplitude
[x
] != 0)
7826 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7828 AdvertisedBenefit
/= DotTicks
;
7832 // distribute healing to all effects, reduce AoE damage
7833 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7835 // 0% bonus for damage and healing spells for leech spells from healing bonus
7836 for(int j
= 0; j
< 3; ++j
)
7838 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7839 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7847 switch (spellProto
->SpellFamilyName
)
7849 case SPELLFAMILY_SHAMAN
:
7850 // Healing stream from totem (add 6% per tick from hill bonus owner)
7851 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7853 // Earth Shield 30% per charge
7854 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7857 case SPELLFAMILY_DRUID
:
7859 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7861 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7862 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7864 // Tranquility triggered spell
7865 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7868 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7871 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7873 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7874 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7877 case SPELLFAMILY_PRIEST
:
7879 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7882 case SPELLFAMILY_PALADIN
:
7883 // Seal and Judgement of Light
7884 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7887 case SPELLFAMILY_WARRIOR
:
7888 case SPELLFAMILY_ROGUE
:
7889 case SPELLFAMILY_HUNTER
:
7894 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7896 // Spellmod SpellDamage
7897 float SpellModSpellDamage
= 100.0f
;
7899 if(Player
* modOwner
= GetSpellModOwner())
7900 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7902 SpellModSpellDamage
/= 100.0f
;
7904 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7907 // use float as more appropriate for negative values and percent applying
7908 float heal
= healamount
+ ActualBenefit
;
7910 // TODO: check for ALL/SPELLS type
7911 // Healing done percent
7912 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7913 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7914 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7916 // apply spellmod to Done amount
7917 if(Player
* modOwner
= GetSpellModOwner())
7918 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7920 // Healing Wave cast
7921 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7923 // Search for Healing Way on Victim (stack up to 3 time)
7925 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7926 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7927 if((*itr
)->GetId() == 29203)
7928 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7931 heal
= heal
* (100 + pctMod
) / 100;
7934 // Healing taken percent
7935 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7937 heal
*= (100.0f
+ minval
) / 100.0f
;
7939 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7941 heal
*= (100.0f
+ maxval
) / 100.0f
;
7943 if (heal
< 0) heal
= 0;
7945 return uint32(heal
);
7948 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7950 int32 AdvertisedBenefit
= 0;
7952 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7953 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7954 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7955 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7957 // Healing bonus of spirit, intellect and strength
7958 if (GetTypeId() == TYPEID_PLAYER
)
7960 // Healing bonus from stats
7961 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7962 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7964 // stat used dependent from misc value (stat index)
7965 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7966 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7969 // ... and attack power
7970 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7971 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7972 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7973 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7975 return AdvertisedBenefit
;
7978 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7980 int32 AdvertisedBenefit
= 0;
7981 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7982 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7983 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7984 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7985 return AdvertisedBenefit
;
7988 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7990 // no charges dependent checks
7991 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7992 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7993 if(itr
->type
& shoolMask
)
7996 // charges dependent checks
7997 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7998 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
8000 if(itr
->type
& shoolMask
)
8004 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
8005 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
8007 if((*auraItr
)->GetId()==itr
->spellId
)
8009 if((*auraItr
)->m_procCharges
> 0)
8011 --(*auraItr
)->m_procCharges
;
8012 if((*auraItr
)->m_procCharges
==0)
8013 RemoveAurasDueToSpell(itr
->spellId
);
8026 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8033 //FIX ME this hack: don't get feared if stunned
8034 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8036 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8040 // not have spells with charges currently
8041 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8042 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8043 if(itr
->type
== spellInfo
->Dispel
)
8046 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8048 // not have spells with charges currently
8049 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8050 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8051 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8052 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8056 // charges dependent checks
8058 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8059 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8061 if(itr
->type
== spellInfo
->Mechanic
)
8065 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8066 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8068 if((*auraItr
)->GetId()==itr
->spellId
)
8070 if((*auraItr
)->m_procCharges
> 0)
8072 --(*auraItr
)->m_procCharges
;
8073 if((*auraItr
)->m_procCharges
==0)
8074 RemoveAurasDueToSpell(itr
->spellId
);
8087 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8089 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8090 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8091 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8092 if(itr
->type
== effect
)
8095 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8096 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8097 if(itr
->type
== mechanic
)
8103 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8108 uint32 family
= spellInfo
->SpellFamilyName
;
8109 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8111 if((family
== 5 && flags
== 256) || //Searing Pain
8112 (family
== 6 && flags
== 8192) || //Mind Blast
8113 (family
== 11 && flags
== 1048576)) //Earth Shock
8119 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8127 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8129 // Taken/Done fixed damage bonus auras
8130 int32 DoneFlatBenefit
= 0;
8131 int32 TakenFlatBenefit
= 0;
8133 // ..done (for creature type by mask) in taken
8134 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8135 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8136 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8137 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8140 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8142 // ..done (base at attack power for marked target and base at attack power for creature type)
8144 if(attType
== RANGED_ATTACK
)
8146 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8148 // ..done (base at attack power and creature type)
8149 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8150 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8151 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8152 APbonus
+= (*i
)->GetModifier()->m_amount
;
8156 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8158 // ..done (base at attack power and creature type)
8159 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8160 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8161 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8162 APbonus
+= (*i
)->GetModifier()->m_amount
;
8165 if (APbonus
!=0) // Can be negative
8167 bool normalized
= false;
8170 for (uint8 i
= 0; i
<3;i
++)
8172 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8180 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8184 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8185 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8186 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8187 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8189 if(attType
!=RANGED_ATTACK
)
8190 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8192 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8194 // Done/Taken total percent damage auras
8195 float DoneTotalMod
= 1;
8196 float TakenTotalMod
= 1;
8199 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8200 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8202 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8203 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8204 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8205 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8208 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8209 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8210 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8211 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8213 // .. taken pct: dummy auras
8214 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8215 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8217 switch((*i
)->GetSpellProto()->SpellIconID
)
8221 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8223 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8225 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8226 if (mod
< (*i
)->GetModifier()->m_amount
)
8227 mod
= (*i
)->GetModifier()->m_amount
;
8228 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8233 if(spellProto
==NULL
)
8235 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8236 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8237 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8242 // .. taken pct: class scripts
8243 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8244 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8246 switch((*i
)->GetMiscValue())
8248 case 6427: case 6428: // Dirty Deeds
8249 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8251 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8252 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8254 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8258 // effect 0 have expected value but in negative state
8259 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8265 if(attType
!= RANGED_ATTACK
)
8267 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8268 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8269 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8273 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8274 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8275 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8278 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8280 // apply spellmod to Done damage
8283 if(Player
* modOwner
= GetSpellModOwner())
8284 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8287 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8289 // bonus result can be negative
8290 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8293 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8297 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8300 if(itr
->type
== type
)
8302 m_spellImmune
[op
].erase(itr
);
8303 next
= m_spellImmune
[op
].begin();
8307 Immune
.spellId
= spellId
;
8309 m_spellImmune
[op
].push_back(Immune
);
8313 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8315 if(itr
->spellId
== spellId
)
8317 m_spellImmune
[op
].erase(itr
);
8325 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8327 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8329 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8330 RemoveAurasWithDispelType(type
);
8333 float Unit::GetWeaponProcChance() const
8335 // normalized proc chance for weapon attack speed
8337 if(isAttackReady(BASE_ATTACK
))
8338 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8339 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8340 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8344 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8346 // proc per minute chance calculation
8347 if (PPM
<= 0) return 0.0f
;
8348 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8352 void Unit::Mount(uint32 mount
)
8357 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8359 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8361 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8364 if(GetTypeId() == TYPEID_PLAYER
)
8366 Pet
* pet
= GetPet();
8369 if(pet
->isControlled())
8371 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8372 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8375 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8378 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8382 void Unit::Unmount()
8387 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8389 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8390 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8392 // only resummon old pet if the player is already added to a map
8393 // this prevents adding a pet to a not created map which would otherwise cause a crash
8394 // (it could probably happen when logging in after a previous crash)
8395 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8397 Pet
* NewPet
= new Pet
;
8398 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8401 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8405 void Unit::SetInCombatWith(Unit
* enemy
)
8407 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8410 SetInCombatState(true);
8415 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8417 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8418 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8420 SetInCombatState(true);
8424 SetInCombatState(false);
8427 void Unit::SetInCombatState(bool PvP
)
8429 // only alive units can be in combat
8434 m_CombatTimer
= 5000;
8435 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8437 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8438 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8441 void Unit::ClearInCombat()
8444 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8446 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8447 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8449 // Player's state will be cleared in Player::UpdateContestedPvP
8450 if(GetTypeId()!=TYPEID_PLAYER
)
8451 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8454 bool Unit::isTargetableForAttack() const
8456 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8459 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8462 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8465 int32
Unit::ModifyHealth(int32 dVal
)
8472 int32 curHealth
= (int32
)GetHealth();
8474 int32 val
= dVal
+ curHealth
;
8481 int32 maxHealth
= (int32
)GetMaxHealth();
8486 gain
= val
- curHealth
;
8488 else if(curHealth
!= maxHealth
)
8490 SetHealth(maxHealth
);
8491 gain
= maxHealth
- curHealth
;
8497 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8504 int32 curPower
= (int32
)GetPower(power
);
8506 int32 val
= dVal
+ curPower
;
8513 int32 maxPower
= (int32
)GetMaxPower(power
);
8517 SetPower(power
,val
);
8518 gain
= val
- curPower
;
8520 else if(curPower
!= maxPower
)
8522 SetPower(power
,maxPower
);
8523 gain
= maxPower
- curPower
;
8529 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8534 // Always can see self
8538 // player visible for other player if not logout and at same transport
8539 // including case when player is out of world
8540 bool at_same_transport
=
8541 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8542 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8543 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8544 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8547 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8550 // forbidden to seen (at GM respawn command)
8551 if(m_Visibility
==VISIBILITY_RESPAWN
)
8554 // always seen by owner
8555 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8558 // Grid dead/alive checks
8559 if( u
->GetTypeId()==TYPEID_PLAYER
)
8561 // non visible at grid for any stealth state
8562 if(!IsVisibleInGridForPlayer((Player
*)u
))
8565 // if player is dead then he can't detect anyone in any cases
8571 // all dead creatures/players not visible for any creatures
8572 if(!u
->isAlive() || !isAlive())
8576 // different visible distance checks
8577 if(u
->isInFlight()) // what see player in flight
8579 // use object grey distance for all (only see objects any way)
8580 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8583 else if(!isAlive()) // distance for show body
8585 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8588 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8590 if(u
->GetTypeId()==TYPEID_PLAYER
)
8592 // Players far than max visible distance for player or not in our map are not visible too
8593 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8598 // Units far than max visible distance for creature or not in our map are not visible too
8599 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8603 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8605 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8606 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8609 else // distance for show creature
8611 // Units far than max visible distance for creature or not in our map are not visible too
8612 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8616 // Visible units, always are visible for all units, except for units under invisibility
8617 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8620 // GMs see any players, not higher GMs and all units
8621 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8623 if(GetTypeId() == TYPEID_PLAYER
)
8624 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8629 // non faction visibility non-breakable for non-GMs
8630 if (m_Visibility
== VISIBILITY_OFF
)
8634 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8636 // detectable invisibility case
8638 // Invisible units, always are visible for units under same invisibility type
8639 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8640 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8641 u
->canDetectInvisibilityOf(this) ||
8642 // Units that can detect invisibility always are visible for units that can be detected
8643 canDetectInvisibilityOf(u
) ))
8648 // special cases for always overwrite invisibility/stealth
8649 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8652 if (!u
->IsHostileTo(this))
8654 // 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)
8655 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8657 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8660 // else apply same rules as for hostile case (detecting check for stealth)
8666 // Hunter mark functionality
8667 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8668 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8669 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8672 // else apply detecting check for stealth
8675 // none other cases for detect invisibility, so invisible
8679 // else apply stealth detecting check
8682 // unit got in stealth in this moment and must ignore old detected state
8683 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8686 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8687 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8690 // NOW ONLY STEALTH CASE
8692 // stealth and detected and visible for some seconds
8693 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8696 //if in non-detect mode then invisible for unit
8702 // If is attacked then stealth is lost, some creature can use stealth too
8703 if( !getAttackers().empty() )
8706 // If there is collision rogue is seen regardless of level difference
8707 // TODO: check sizes in DB
8708 float distance
= GetDistance(u
);
8709 if (distance
< 0.24f
)
8712 //If a mob or player is stunned he will not be able to detect stealth
8713 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8716 // Creature can detect target only in aggro radius
8717 if(u
->GetTypeId() != TYPEID_PLAYER
)
8719 //Always invisible from back and out of aggro range
8720 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8726 //Always invisible from back
8727 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8732 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8733 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8735 //Calculation if target is in front
8737 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8738 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8740 //Visible distance is modified by
8741 //-Level Diff (every level diff = 1.0f in visible distance)
8742 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8744 //This allows to check talent tree and will add addition stealth dependent on used points)
8745 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8749 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8750 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8751 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8753 if(distance
> visibleDistance
)
8757 // Now check is target visible with LoS
8759 u
->GetPosition(ox
,oy
,oz
);
8760 return IsWithinLOS(ox
,oy
,oz
);
8763 void Unit::SetVisibility(UnitVisibility x
)
8769 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8771 if(GetTypeId()==TYPEID_PLAYER
)
8772 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8774 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8778 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8780 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8782 for(uint32 i
= 0; i
< 10; ++i
)
8784 if(((1 << i
) & mask
)==0)
8787 // find invisibility level
8788 uint32 invLevel
= 0;
8789 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8790 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8791 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8792 invLevel
= (*itr
)->GetModifier()->m_amount
;
8794 // find invisibility detect level
8795 uint32 detectLevel
= 0;
8796 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8797 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8798 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8799 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8801 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8803 detectLevel
= ((Player
*)this)->GetDrunkValue();
8806 if(invLevel
<= detectLevel
)
8814 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8816 int32 main_speed_mod
= 0;
8817 float stack_bonus
= 1.0f
;
8818 float non_stack_bonus
= 1.0f
;
8826 if (IsMounted()) // Use on mount auras
8828 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8829 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8830 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8834 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8835 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8836 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8844 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8851 if (IsMounted()) // Use on mount auras
8852 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8853 else // Use not mount (shapeshift for example) auras (should stack)
8854 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8855 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8856 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8862 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8866 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8867 // now we ready for speed calculation
8868 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8876 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8877 // TODO: possible affect only on MOVE_RUN
8878 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8880 // Use speed from aura
8881 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8882 if (speed
> max_speed
)
8891 // Apply strongest slow aura mod to speed
8892 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8894 speed
*=(100.0f
+ slow
)/100.0f
;
8895 SetSpeed(mtype
, speed
, forced
);
8898 float Unit::GetSpeed( UnitMoveType mtype
) const
8900 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8903 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8908 // Update speed only on change
8909 if (m_speed_rate
[mtype
] == rate
)
8912 m_speed_rate
[mtype
] = rate
;
8914 propagateSpeedChange();
8916 // Send speed change packet only for player
8917 if (GetTypeId()!=TYPEID_PLAYER
)
8926 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8929 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8932 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8935 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8938 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8941 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8944 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8947 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8950 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8954 data
.append(GetPackGUID());
8955 data
<< uint32(0); //movement flags
8956 data
<< uint16(0); //unk
8957 data
<< uint32(getMSTime());
8958 data
<< float(GetPositionX());
8959 data
<< float(GetPositionY());
8960 data
<< float(GetPositionZ());
8961 data
<< float(GetOrientation());
8962 data
<< uint32(0); //flag unk
8963 data
<< float(GetSpeed(mtype
));
8964 SendMessageToSet( &data
, true );
8968 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8969 // and do it only for real sent packets and use run for run/mounted as client expected
8970 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8974 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8977 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8980 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8983 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8986 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8989 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8992 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8995 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8998 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
9001 data
.append(GetPackGUID());
9003 if (mtype
== MOVE_RUN
)
9004 data
<< uint8(0); // new 2.1.0
9005 data
<< float(GetSpeed(mtype
));
9006 SendMessageToSet( &data
, true );
9008 if(Pet
* pet
= GetPet())
9009 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9012 void Unit::SetHover(bool on
)
9015 CastSpell(this,11010,true);
9017 RemoveAurasDueToSpell(11010);
9020 void Unit::setDeathState(DeathState s
)
9022 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9026 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9028 if(IsNonMeleeSpellCasted(false))
9029 InterruptNonMeleeSpells(false);
9034 RemoveAllAurasOnDeath();
9035 UnsummonAllTotems();
9037 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9038 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9039 // remove aurastates allowing special moves
9040 ClearAllReactives();
9041 ClearDiminishings();
9043 else if(s
== JUST_ALIVED
)
9045 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9048 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9050 //_ApplyAllAuraMods();
9055 /*########################################
9057 ######## AGGRO SYSTEM ########
9059 ########################################*/
9060 bool Unit::CanHaveThreatList() const
9062 // only creatures can have threat list
9063 if( GetTypeId() != TYPEID_UNIT
)
9066 // only alive units can have threat list
9070 // pets and totems can not have threat list
9071 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() || ((Creature
*)this)->isVehicle() )
9077 //======================================================================
9079 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9081 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9084 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9086 return threat
* m_threatModifier
[school
];
9089 //======================================================================
9091 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9093 // Only mobs can manage threat lists
9094 if(CanHaveThreatList())
9095 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9098 //======================================================================
9100 void Unit::DeleteThreatList()
9102 m_ThreatManager
.clearReferences();
9105 //======================================================================
9107 void Unit::TauntApply(Unit
* taunter
)
9109 assert(GetTypeId()== TYPEID_UNIT
);
9111 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9114 if(!CanHaveThreatList())
9117 Unit
*target
= getVictim();
9118 if(target
&& target
== taunter
)
9121 SetInFront(taunter
);
9122 if (((Creature
*)this)->AI())
9123 ((Creature
*)this)->AI()->AttackStart(taunter
);
9125 m_ThreatManager
.tauntApply(taunter
);
9128 //======================================================================
9130 void Unit::TauntFadeOut(Unit
*taunter
)
9132 assert(GetTypeId()== TYPEID_UNIT
);
9134 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9137 if(!CanHaveThreatList())
9140 Unit
*target
= getVictim();
9141 if(!target
|| target
!= taunter
)
9144 if(m_ThreatManager
.isThreatListEmpty())
9146 if(((Creature
*)this)->AI())
9147 ((Creature
*)this)->AI()->EnterEvadeMode();
9151 m_ThreatManager
.tauntFadeOut(taunter
);
9152 target
= m_ThreatManager
.getHostilTarget();
9154 if (target
&& target
!= taunter
)
9157 if (((Creature
*)this)->AI())
9158 ((Creature
*)this)->AI()->AttackStart(target
);
9162 //======================================================================
9164 bool Unit::SelectHostilTarget()
9166 //function provides main threat functionality
9167 //next-victim-selection algorithm and evade mode are called
9168 //threat list sorting etc.
9170 assert(GetTypeId()== TYPEID_UNIT
);
9171 Unit
* target
= NULL
;
9173 //This function only useful once AI has been initialized
9174 if (!((Creature
*)this)->AI())
9177 if(!m_ThreatManager
.isThreatListEmpty())
9179 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9181 target
= m_ThreatManager
.getHostilTarget();
9187 if(!hasUnitState(UNIT_STAT_STUNNED
))
9189 ((Creature
*)this)->AI()->AttackStart(target
);
9193 // no target but something prevent go to evade mode
9194 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9197 // last case when creature don't must go to evade mode:
9198 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9199 // for example at owner command to pet attack some far away creature
9200 // Note: creature not have targeted movement generator but have attacker in this case
9201 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9203 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9205 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9210 // enter in evade mode in other case
9211 ((Creature
*)this)->AI()->EnterEvadeMode();
9216 //======================================================================
9217 //======================================================================
9218 //======================================================================
9220 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9222 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9224 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9226 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9227 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9228 level
= spellProto
->maxLevel
;
9230 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9231 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9232 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9233 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9234 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9236 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9237 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9238 int32 value
= basePoints
+ randvalue
;
9240 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9241 value
+= (int32
)(comboDamage
* comboPoints
);
9243 if(Player
* modOwner
= GetSpellModOwner())
9245 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9246 switch(effect_index
)
9249 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9252 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9255 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9260 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9261 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9262 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9263 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9268 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9270 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9272 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9274 int32 minduration
= GetSpellDuration(spellProto
);
9275 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9279 if( minduration
!= -1 && minduration
!= maxduration
)
9280 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9282 duration
= minduration
;
9286 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9287 // Find total mod value (negative bonus)
9288 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9289 // Find max mod (negative bonus)
9290 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9292 int32 durationMod
= 0;
9293 // Select strongest negative mod
9294 if (durationMod_always
> durationMod_not_stack
)
9295 durationMod
= durationMod_not_stack
;
9297 durationMod
= durationMod_always
;
9299 if (durationMod
!= 0)
9300 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9302 if (duration
< 0) duration
= 0;
9308 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9310 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9312 if(i
->DRGroup
!= group
)
9316 return DIMINISHING_LEVEL_1
;
9319 return DIMINISHING_LEVEL_1
;
9321 // If last spell was casted more than 15 seconds ago - reset the count.
9322 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9324 i
->hitCount
= DIMINISHING_LEVEL_1
;
9325 return DIMINISHING_LEVEL_1
;
9327 // or else increase the count.
9330 return DiminishingLevels(i
->hitCount
);
9333 return DIMINISHING_LEVEL_1
;
9336 void Unit::IncrDiminishing(DiminishingGroup group
)
9338 // Checking for existing in the table
9339 bool IsExist
= false;
9340 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9342 if(i
->DRGroup
!= group
)
9346 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9353 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9356 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9358 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9361 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9362 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9364 // test pet/charm masters instead pets/charmeds
9365 Unit
const* targetOwner
= GetCharmerOrOwner();
9366 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9368 Unit
const* target
= targetOwner
? targetOwner
: this;
9369 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9371 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9377 // Some diminishings applies to mobs too (for example, Stun)
9378 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9380 DiminishingLevels diminish
= Level
;
9383 case DIMINISHING_LEVEL_1
: break;
9384 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9385 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9386 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9391 duration
= int32(duration
* mod
);
9394 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9396 // Checking for existing in the table
9397 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9399 if(i
->DRGroup
!= group
)
9402 i
->hitTime
= getMSTime();
9413 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9415 return ObjectAccessor::GetUnit(object
,guid
);
9418 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9420 return isVisibleForOrDetect(u
,false,inVisibleList
);
9423 uint32
Unit::GetCreatureType() const
9425 if(GetTypeId() == TYPEID_PLAYER
)
9427 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9428 if(ssEntry
&& ssEntry
->creatureType
> 0)
9429 return ssEntry
->creatureType
;
9431 return CREATURE_TYPE_HUMANOID
;
9434 return ((Creature
*)this)->GetCreatureInfo()->type
;
9437 /*#######################################
9439 ######## STAT SYSTEM ########
9441 #######################################*/
9443 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9445 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9447 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9453 switch(modifierType
)
9457 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9461 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9464 val
= (100.0f
+ amount
) / 100.0f
;
9465 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9472 if(!CanModifyStats())
9477 case UNIT_MOD_STAT_STRENGTH
:
9478 case UNIT_MOD_STAT_AGILITY
:
9479 case UNIT_MOD_STAT_STAMINA
:
9480 case UNIT_MOD_STAT_INTELLECT
:
9481 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9483 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9484 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9488 case UNIT_MOD_FOCUS
:
9489 case UNIT_MOD_ENERGY
:
9490 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9492 case UNIT_MOD_RESISTANCE_HOLY
:
9493 case UNIT_MOD_RESISTANCE_FIRE
:
9494 case UNIT_MOD_RESISTANCE_NATURE
:
9495 case UNIT_MOD_RESISTANCE_FROST
:
9496 case UNIT_MOD_RESISTANCE_SHADOW
:
9497 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9499 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9500 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9502 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9503 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9504 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9513 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9515 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9517 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9521 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9524 return m_auraModifiersGroup
[unitMod
][modifierType
];
9527 float Unit::GetTotalStatValue(Stats stat
) const
9529 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9531 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9534 // value = ((base_value * base_pct) + total_value) * total_pct
9535 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9536 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9537 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9538 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9543 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9545 if(unitMod
>= UNIT_MOD_END
)
9547 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9551 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9554 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9555 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9556 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9557 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9562 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9564 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9568 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9569 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9570 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9571 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9572 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9573 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9582 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9584 Stats stat
= STAT_STRENGTH
;
9588 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9589 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9590 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9591 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9592 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9601 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9603 Powers power
= POWER_MANA
;
9607 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9608 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9609 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9610 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9611 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9620 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9622 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9624 float val
= GetTotalAuraModValue(unitMod
);
9631 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9633 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9636 return m_weaponDamage
[attType
][type
];
9639 void Unit::SetLevel(uint32 lvl
)
9641 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9644 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9645 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9648 void Unit::SetHealth(uint32 val
)
9650 uint32 maxHealth
= GetMaxHealth();
9654 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9657 if(GetTypeId() == TYPEID_PLAYER
)
9659 if(((Player
*)this)->GetGroup())
9660 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9662 else if(((Creature
*)this)->isPet())
9664 Pet
*pet
= ((Pet
*)this);
9665 if(pet
->isControlled())
9667 Unit
*owner
= GetOwner();
9668 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9669 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9674 void Unit::SetMaxHealth(uint32 val
)
9676 uint32 health
= GetHealth();
9677 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9680 if(GetTypeId() == TYPEID_PLAYER
)
9682 if(((Player
*)this)->GetGroup())
9683 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9685 else if(((Creature
*)this)->isPet())
9687 Pet
*pet
= ((Pet
*)this);
9688 if(pet
->isControlled())
9690 Unit
*owner
= GetOwner();
9691 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9692 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9700 void Unit::SetPower(Powers power
, uint32 val
)
9702 uint32 maxPower
= GetMaxPower(power
);
9706 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9708 WorldPacket
data(SMSG_POWER_UPDATE
);
9709 data
.append(GetPackGUID());
9710 data
<< uint8(power
);
9711 data
<< uint32(val
);
9712 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9715 if(GetTypeId() == TYPEID_PLAYER
)
9717 if(((Player
*)this)->GetGroup())
9718 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9720 else if(((Creature
*)this)->isPet())
9722 Pet
*pet
= ((Pet
*)this);
9723 if(pet
->isControlled())
9725 Unit
*owner
= GetOwner();
9726 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9727 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9730 // Update the pet's character sheet with happiness damage bonus
9731 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9733 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9738 void Unit::SetMaxPower(Powers power
, uint32 val
)
9740 uint32 cur_power
= GetPower(power
);
9741 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9744 if(GetTypeId() == TYPEID_PLAYER
)
9746 if(((Player
*)this)->GetGroup())
9747 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9749 else if(((Creature
*)this)->isPet())
9751 Pet
*pet
= ((Pet
*)this);
9752 if(pet
->isControlled())
9754 Unit
*owner
= GetOwner();
9755 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9756 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9761 SetPower(power
, val
);
9764 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9766 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9769 if(GetTypeId() == TYPEID_PLAYER
)
9771 if(((Player
*)this)->GetGroup())
9772 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9774 else if(((Creature
*)this)->isPet())
9776 Pet
*pet
= ((Pet
*)this);
9777 if(pet
->isControlled())
9779 Unit
*owner
= GetOwner();
9780 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9781 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9786 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9788 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9791 if(GetTypeId() == TYPEID_PLAYER
)
9793 if(((Player
*)this)->GetGroup())
9794 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9796 else if(((Creature
*)this)->isPet())
9798 Pet
*pet
= ((Pet
*)this);
9799 if(pet
->isControlled())
9801 Unit
*owner
= GetOwner();
9802 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9803 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9808 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9810 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9812 tAuraProcTriggerDamage
.push_back(aura
);
9814 tAuraProcTriggerDamage
.remove(aura
);
9817 uint32
Unit::GetCreatePowers( Powers power
) const
9819 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9822 case POWER_MANA
: return GetCreateMana();
9823 case POWER_RAGE
: return 1000;
9824 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9825 case POWER_ENERGY
: return 100;
9826 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9827 case POWER_RUNIC_POWER
: return 1000;
9833 void Unit::AddToWorld()
9835 Object::AddToWorld();
9838 void Unit::RemoveFromWorld()
9843 RemoveNotOwnSingleTargetAuras();
9846 Object::RemoveFromWorld();
9849 void Unit::CleanupsBeforeDelete()
9851 if(m_uint32Values
) // only for fully created object
9853 InterruptNonMeleeSpells(true);
9854 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9856 ClearComboPointHolders();
9858 getHostilRefManager().setOnlineOfflineState(false);
9860 RemoveAllGameObjects();
9861 RemoveAllDynObjects();
9862 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9867 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9870 m_charmInfo
= new CharmInfo(charm
);
9874 CharmInfo::CharmInfo(Unit
* unit
)
9875 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9877 for(int i
=0; i
<4; ++i
)
9879 m_charmspells
[i
].spellId
= 0;
9880 m_charmspells
[i
].active
= ACT_DISABLED
;
9884 void CharmInfo::InitPetActionBar()
9886 // the first 3 SpellOrActions are attack, follow and stay
9887 for(uint32 i
= 0; i
< 3; i
++)
9889 PetActionBar
[i
].Type
= ACT_COMMAND
;
9890 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9892 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9893 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9895 for(uint32 i
=0; i
< 4; i
++)
9897 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9898 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9902 void CharmInfo::InitEmptyActionBar()
9904 for(uint32 x
= 1; x
< 10; ++x
)
9906 PetActionBar
[x
].Type
= ACT_PASSIVE
;
9907 PetActionBar
[x
].SpellOrAction
= 0;
9909 PetActionBar
[0].Type
= ACT_COMMAND
;
9910 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9913 void CharmInfo::InitPossessCreateSpells()
9915 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9918 InitEmptyActionBar(); //charm action bar
9920 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9922 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9923 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9925 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_PASSIVE
);
9929 void CharmInfo::InitCharmCreateSpells()
9931 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9933 InitEmptyActionBar();
9939 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9941 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9942 m_charmspells
[x
].spellId
= spellId
;
9947 if (IsPassiveSpell(spellId
))
9949 m_unit
->CastSpell(m_unit
, spellId
, true);
9950 m_charmspells
[x
].active
= ACT_PASSIVE
;
9954 ActiveStates newstate
;
9955 bool onlyselfcast
= true;
9956 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9958 if(!spellInfo
) onlyselfcast
= false;
9959 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9961 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9962 onlyselfcast
= false;
9965 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9966 newstate
= ACT_DISABLED
;
9968 newstate
= ACT_PASSIVE
;
9970 AddSpellToAB(0, spellId
, newstate
);
9975 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9977 for(uint8 i
= 0; i
< 10; i
++)
9979 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_PASSIVE
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9981 PetActionBar
[i
].SpellOrAction
= newid
;
9984 if(newstate
== ACT_DECIDE
)
9985 PetActionBar
[i
].Type
= ACT_DISABLED
;
9987 PetActionBar
[i
].Type
= newstate
;
9996 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9998 if(IsPassiveSpell(spellid
))
10001 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
10003 if(spellid
== m_charmspells
[x
].spellId
)
10005 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
10010 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10012 m_petnumber
= petnumber
;
10014 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10016 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10019 bool Unit::isFrozen() const
10021 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10022 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10023 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10028 struct ProcTriggeredData
10030 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
10031 : triggeredByAura(_triggeredByAura
),
10032 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10033 cooldown(_cooldown
)
10036 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10037 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10038 uint32 cooldown
; // possible hidden cooldown
10041 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10043 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10045 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10047 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10048 ProcTriggeredList procTriggered
;
10050 AuraList
const& auras
= GetAurasByType(*aur
);
10051 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10057 uint32 cooldown
; // returned at next line
10058 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10061 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10064 // Handle effects proceed this time
10065 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10067 // Some auras can be deleted in function called in this loop (except first, ofc)
10068 // Until storing auras in std::multimap to hard check deleting by another way
10069 if(i
!= procTriggered
.begin())
10071 bool found
= false;
10072 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10073 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10074 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10076 if(itr
->second
==i
->triggeredByAura
)
10085 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
);
10086 sLog
.outError("It can be deleted one from early processed auras:");
10087 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10088 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10089 sLog
.outError(" <end of list>");
10094 /// this is aura triggering code call
10095 Aura
* triggeredByAura
= i
->triggeredByAura
;
10097 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10098 /// used in speedup code check before check aura existance.
10099 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10101 /// success in event proccesing
10102 /// used in speedup code check before check aura existance.
10103 bool casted
= false;
10105 /// process triggered code
10108 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10110 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10111 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10112 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10115 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10117 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10118 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10119 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10120 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10124 case SPELL_AURA_DUMMY
:
10126 uint32 effect
= triggeredByAura
->GetEffIndex();
10127 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10128 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10129 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10132 case SPELL_AURA_PRAYER_OF_MENDING
:
10134 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10135 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10137 casted
= HandleMeandingAuraProc(triggeredByAura
);
10140 case SPELL_AURA_MOD_HASTE
:
10142 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10143 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10144 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10147 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10149 // nothing do, just charges counter
10150 // but count only in case appropriate school damage
10151 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10154 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10156 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s class script aura of spell %u)",
10157 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10158 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10163 // nothing do, just charges counter
10169 /// Update charge (aura can be removed by triggers)
10170 if(casted
&& triggeredByAuraWithCharges
)
10172 /// need re-found aura (can be dropped by triggers)
10173 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10174 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10175 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10177 if(itr
->second
== triggeredByAura
) // pointer still valid
10179 if(triggeredByAura
->m_procCharges
> 0)
10180 triggeredByAura
->m_procCharges
-= 1;
10182 triggeredByAura
->UpdateAuraCharges();
10189 /// Safely remove auras with zero charges
10190 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10193 if((*i
)->m_procCharges
== 0)
10195 RemoveAurasDueToSpell((*i
)->GetId());
10196 next
= auras
.begin();
10202 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10204 return SPELL_SCHOOL_MASK_NORMAL
;
10207 Player
* Unit::GetSpellModOwner()
10209 if(GetTypeId()==TYPEID_PLAYER
)
10210 return (Player
*)this;
10211 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10213 Unit
* owner
= GetOwner();
10214 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10215 return (Player
*)owner
;
10220 ///----------Pet responses methods-----------------
10221 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10223 Unit
*owner
= GetCharmerOrOwner();
10224 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10227 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10228 data
<< uint8(0); // cast count?
10229 data
<< uint32(spellid
);
10230 data
<< uint8(msg
);
10231 // uint32 for some reason
10232 // uint32 for some reason
10233 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10236 void Unit::SendPetActionFeedback (uint8 msg
)
10238 Unit
* owner
= GetOwner();
10239 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10242 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10243 data
<< uint8(msg
);
10244 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10247 void Unit::SendPetTalk (uint32 pettalk
)
10249 Unit
* owner
= GetOwner();
10250 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10253 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10254 data
<< uint64(GetGUID());
10255 data
<< uint32(pettalk
);
10256 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10259 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10261 Unit
* owner
= GetOwner();
10262 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10265 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10266 data
<< uint64(GetGUID());
10267 data
<< uint8(0x0); // flags (0x1, 0x2)
10268 data
<< uint32(spellid
);
10269 data
<< uint32(cooltime
);
10271 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10274 void Unit::SendPetClearCooldown (uint32 spellid
)
10276 Unit
* owner
= GetOwner();
10277 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10280 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10281 data
<< uint32(spellid
);
10282 data
<< uint64(GetGUID());
10283 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10286 void Unit::SendPetAIReaction(uint64 guid
)
10288 Unit
* owner
= GetOwner();
10289 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10292 WorldPacket
data(SMSG_AI_REACTION
, 12);
10293 data
<< uint64(guid
) << uint32(00000002);
10294 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10297 ///----------End of Pet responses methods----------
10299 void Unit::StopMoving()
10301 clearUnitState(UNIT_STAT_MOVING
);
10303 // send explicit stop packet
10304 // rely on vmaps here because for example stormwind is in air
10305 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10306 //if (fabs(GetPositionZ() - z) < 2.0f)
10307 // Relocate(GetPositionX(), GetPositionY(), z);
10308 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10310 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10312 // update position and orientation;
10314 BuildHeartBeatMsg(&data
);
10315 SendMessageToSet(&data
,false);
10318 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10322 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10325 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10327 GetMotionMaster()->MovementExpired(false);
10328 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10330 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10332 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10336 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10338 GetMotionMaster()->MovementExpired(false);
10340 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10342 // restore appropriate movement generator
10344 GetMotionMaster()->MoveChase(getVictim());
10346 GetMotionMaster()->Initialize();
10348 // attack caster if can
10349 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10350 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10351 ((Creature
*)this)->AI()->AttackStart(caster
);
10355 if (GetTypeId() == TYPEID_PLAYER
)
10356 ((Player
*)this)->SetClientControl(this, !apply
);
10359 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10363 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10365 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10367 GetMotionMaster()->MoveConfused();
10371 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10373 GetMotionMaster()->MovementExpired(false);
10375 if (GetTypeId() == TYPEID_UNIT
)
10377 // if in combat restore movement generator
10379 GetMotionMaster()->MoveChase(getVictim());
10383 if(GetTypeId() == TYPEID_PLAYER
)
10384 ((Player
*)this)->SetClientControl(this, !apply
);
10387 bool Unit::IsSitState() const
10389 uint8 s
= getStandState();
10390 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10391 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10392 s
== PLAYER_STATE_SIT
;
10395 bool Unit::IsStandState() const
10397 uint8 s
= getStandState();
10398 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10401 void Unit::SetStandState(uint8 state
)
10403 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10405 if (IsStandState())
10406 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10408 if(GetTypeId()==TYPEID_PLAYER
)
10410 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10411 data
<< (uint8
)state
;
10412 ((Player
*)this)->GetSession()->SendPacket(&data
);
10416 bool Unit::IsPolymorphed() const
10418 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10421 void Unit::SetDisplayId(uint32 modelId
)
10423 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10425 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10427 Pet
*pet
= ((Pet
*)this);
10428 if(!pet
->isControlled())
10430 Unit
*owner
= GetOwner();
10431 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10432 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10436 void Unit::ClearComboPointHolders()
10438 while(!m_ComboPointHolders
.empty())
10440 uint32 lowguid
= *m_ComboPointHolders
.begin();
10442 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10443 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10444 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10446 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10450 void Unit::ClearAllReactives()
10453 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10454 m_reactiveTimer
[i
] = 0;
10456 if (HasAuraState( AURA_STATE_DEFENSE
))
10457 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10458 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10459 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10460 if (HasAuraState( AURA_STATE_CRIT
))
10461 ModifyAuraState(AURA_STATE_CRIT
, false);
10462 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10463 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10465 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10466 ((Player
*)this)->ClearComboPoints();
10469 void Unit::UpdateReactives( uint32 p_time
)
10471 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10473 ReactiveType reactive
= ReactiveType(i
);
10475 if(!m_reactiveTimer
[reactive
])
10478 if ( m_reactiveTimer
[reactive
] <= p_time
)
10480 m_reactiveTimer
[reactive
] = 0;
10482 switch ( reactive
)
10484 case REACTIVE_DEFENSE
:
10485 if (HasAuraState(AURA_STATE_DEFENSE
))
10486 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10488 case REACTIVE_HUNTER_PARRY
:
10489 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10490 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10492 case REACTIVE_CRIT
:
10493 if (HasAuraState(AURA_STATE_CRIT
))
10494 ModifyAuraState(AURA_STATE_CRIT
, false);
10496 case REACTIVE_HUNTER_CRIT
:
10497 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10498 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10500 case REACTIVE_OVERPOWER
:
10501 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10502 ((Player
*)this)->ClearComboPoints();
10510 m_reactiveTimer
[reactive
] -= p_time
;
10515 Unit
* Unit::SelectNearbyTarget() const
10517 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10519 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10520 cell
.SetNoCreate();
10522 std::list
<Unit
*> targets
;
10525 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10526 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10528 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10529 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10531 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10532 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10533 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10536 // remove current target
10538 targets
.remove(getVictim());
10540 // remove not LoS targets
10541 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10543 if(!IsWithinLOSInMap(*tIter
))
10545 std::list
<Unit
*>::iterator tIter2
= tIter
;
10547 targets
.erase(tIter2
);
10553 // no appropriate targets
10554 if(targets
.empty())
10558 uint32 rIdx
= urand(0,targets
.size()-1);
10559 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10560 for(uint32 i
= 0; i
< rIdx
; ++i
)
10566 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10570 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10571 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10575 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10576 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10580 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10583 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10585 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10588 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10590 if (CastingTime
> 7000) CastingTime
= 7000;
10591 if (CastingTime
< 1500) CastingTime
= 1500;
10593 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10594 CastingTime
= 3500;
10596 int32 overTime
= 0;
10598 bool DirectDamage
= false;
10599 bool AreaEffect
= false;
10601 for ( uint32 i
=0; i
<3;i
++)
10603 switch ( spellProto
->Effect
[i
] )
10605 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10606 case SPELL_EFFECT_POWER_DRAIN
:
10607 case SPELL_EFFECT_HEALTH_LEECH
:
10608 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10609 case SPELL_EFFECT_POWER_BURN
:
10610 case SPELL_EFFECT_HEAL
:
10611 DirectDamage
= true;
10613 case SPELL_EFFECT_APPLY_AURA
:
10614 switch ( spellProto
->EffectApplyAuraName
[i
] )
10616 case SPELL_AURA_PERIODIC_DAMAGE
:
10617 case SPELL_AURA_PERIODIC_HEAL
:
10618 case SPELL_AURA_PERIODIC_LEECH
:
10619 if ( GetSpellDuration(spellProto
) )
10620 overTime
= GetSpellDuration(spellProto
);
10623 // -5% per additional effect
10631 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10635 // Combined Spells with Both Over Time and Direct Damage
10636 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10638 // mainly for DoTs which are 3500 here otherwise
10639 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10640 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10641 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10642 // Portion to Over Time
10643 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10645 if ( damagetype
== DOT
)
10646 CastingTime
= uint32(CastingTime
* PtOT
);
10647 else if ( PtOT
< 1.0f
)
10648 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10653 // Area Effect Spells receive only half of bonus
10657 // -5% of total per any additional effect
10658 for ( uint8 i
=0; i
<effects
; ++i
)
10660 if ( CastingTime
> 175 )
10662 CastingTime
-= 175;
10671 return CastingTime
;
10674 void Unit::UpdateAuraForGroup(uint8 slot
)
10676 if(GetTypeId() == TYPEID_PLAYER
)
10678 Player
* player
= (Player
*)this;
10679 if(player
->GetGroup())
10681 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10682 player
->SetAuraUpdateMask(slot
);
10685 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10687 Pet
*pet
= ((Pet
*)this);
10688 if(pet
->isControlled())
10690 Unit
*owner
= GetOwner();
10691 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10693 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10694 pet
->SetAuraUpdateMask(slot
);
10700 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10702 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10703 return float(GetAttackTime(attType
))/1000.0f
;
10705 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10707 return 2.4; // fist attack
10709 switch (Weapon
->GetProto()->InventoryType
)
10711 case INVTYPE_2HWEAPON
:
10713 case INVTYPE_RANGED
:
10714 case INVTYPE_RANGEDRIGHT
:
10715 case INVTYPE_THROWN
:
10717 case INVTYPE_WEAPON
:
10718 case INVTYPE_WEAPONMAINHAND
:
10719 case INVTYPE_WEAPONOFFHAND
:
10721 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10725 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10727 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10728 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10729 if ((*itr
)->GetId() == spell_id
)
10735 bool Unit::IsUnderLastManaUseEffect() const
10737 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10740 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10742 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10744 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10747 player
->SetContestedPvPTimer(30000);
10748 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10750 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10751 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10752 // call MoveInLineOfSight for nearby contested guards
10753 SetVisibility(GetVisibility());
10755 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10757 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10758 // call MoveInLineOfSight for nearby contested guards
10759 SetVisibility(GetVisibility());
10763 void Unit::AddPetAura(PetAura
const* petSpell
)
10765 m_petAuras
.insert(petSpell
);
10766 if(Pet
* pet
= GetPet())
10767 pet
->CastPetAura(petSpell
);
10770 void Unit::RemovePetAura(PetAura
const* petSpell
)
10772 m_petAuras
.erase(petSpell
);
10773 if(Pet
* pet
= GetPet())
10774 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10777 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10779 Pet
* pet
= new Pet(HUNTER_PET
);
10781 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10787 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, GetGUID());
10788 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, GetGUID());
10789 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,getFaction());
10790 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10792 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10793 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10795 if(!pet
->InitStatsForLevel(level
))
10797 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10802 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10803 // this enables pet details window (Shift+P)
10804 pet
->AIM_Initialize();
10805 pet
->InitPetCreateSpells();
10806 pet
->SetHealth(pet
->GetMaxHealth());
10811 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10813 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10815 if(!spellProcEvent
)
10817 // used to prevent spam in log about same non-handled spells
10818 static std::set
<uint32
> nonHandledSpellProcSet
;
10820 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10822 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10823 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10826 // spell.dbc use totally different flags, that only can create problems if used.
10830 // Check spellProcEvent data requirements
10831 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10834 // Check if current equipment allows aura to proc
10835 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10837 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10839 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10841 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10844 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10846 // Check if player is wearing shield
10847 Item
*item
= ((Player
*)this)->GetShield(true);
10848 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10853 float chance
= (float)spellProto
->procChance
;
10855 if(Player
* modOwner
= GetSpellModOwner())
10856 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10858 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10860 uint32 WeaponSpeed
= GetAttackTime(attType
);
10861 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10864 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10865 return roll_chance_f(chance
);
10868 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10870 // aura can be deleted at casts
10871 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10872 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10873 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10874 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10877 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10879 // current aura expire
10880 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10882 // next target selection
10883 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10886 if (spellProto
->EffectRadiusIndex
[effIdx
])
10887 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10889 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10891 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10893 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10895 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10897 // aura will applied from caster, but spell casted from current aura holder
10898 SpellModifier
*mod
= new SpellModifier
;
10899 mod
->op
= SPELLMOD_CHARGES
;
10900 mod
->value
= jumps
-5; // negative
10901 mod
->type
= SPELLMOD_FLAT
;
10902 mod
->spellId
= spellProto
->Id
;
10903 mod
->effectId
= effIdx
;
10904 mod
->lastAffected
= NULL
;
10905 mod
->mask
= spellProto
->SpellFamilyFlags
;
10908 caster
->AddSpellMod(mod
, true);
10909 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10910 caster
->AddSpellMod(mod
, false);
10916 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);