2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
49 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
53 1.25f
, // MOVE_RUN_BACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIM_BACK
56 3.141594f
, // MOVE_TURN_RATE
58 4.5f
, // MOVE_FLIGHT_BACK
59 3.14f
// MOVE_PITCH_RATE
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 case CLASS_DEATH_KNIGHT
:
2070 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2074 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2075 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2076 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2078 // apply max/min bounds
2079 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2081 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2084 if ( highEnd
< 0.2f
) //high end limits
2086 if ( highEnd
> 0.99f
)
2089 if(lowEnd
> highEnd
) // prevent negative range size
2092 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2094 *damage
= uint32(reducePercent
* *damage
);
2095 cleanDamage
->damage
+= *damage
;
2096 *hitInfo
|= HITINFO_GLANCING
;
2099 case MELEE_HIT_CRUSHING
:
2101 // 150% normal damage
2102 *damage
+= (*damage
/ 2);
2103 cleanDamage
->damage
= *damage
;
2104 *hitInfo
|= HITINFO_CRUSHING
;
2105 // TODO: victimState, victim animation?
2112 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2113 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2115 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2116 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2119 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2120 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2122 cleanDamage
->damage
+= *blocked_amount
;
2124 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2126 //*hitInfo = 0x00010020;
2127 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2129 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2133 // update at damage Judgement aura duration that applied by attacker at victim
2136 AuraMap
const& vAuras
= pVictim
->GetAuras();
2137 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2139 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2140 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2141 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2143 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2144 (*itr
).second
->SendAuraUpdate(false);
2149 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2151 // victim's damage shield
2152 // yet another hack to fix crashes related to the aura getting removed during iteration
2153 std::set
<Aura
*> alreadyDone
;
2154 uint32 removedAuras
= pVictim
->m_removedAuras
;
2155 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2156 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2159 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2161 alreadyDone
.insert(*i
);
2162 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2163 if (pVictim
->m_removedAuras
> removedAuras
)
2165 removedAuras
= pVictim
->m_removedAuras
;
2166 next
= vDamageShields
.begin();
2172 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2174 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2177 if (!pVictim
->isAlive())
2180 if(IsNonMeleeSpellCasted(false))
2184 if (attType
== BASE_ATTACK
)
2185 hitInfo
= HITINFO_NORMALSWING2
;
2186 else if (attType
== OFF_ATTACK
)
2187 hitInfo
= HITINFO_LEFTSWING
;
2189 return; // ignore ranged case
2191 uint32 extraAttacks
= m_extraAttacks
;
2193 // melee attack spell casted at main hand attack only
2194 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2196 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2198 // not recent extra attack only at any non extra attack (melee spell case)
2199 if(!extra
&& extraAttacks
)
2201 while(m_extraAttacks
)
2203 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2204 if(m_extraAttacks
> 0)
2212 VictimState victimState
= VICTIMSTATE_NORMAL
;
2214 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2215 uint32 blocked_dmg
= 0;
2216 uint32 absorbed_dmg
= 0;
2217 uint32 resisted_dmg
= 0;
2219 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2221 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2223 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2225 // not recent extra attack only at any non extra attack (miss case)
2226 if(!extra
&& extraAttacks
)
2228 while(m_extraAttacks
)
2230 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2231 if(m_extraAttacks
> 0)
2239 uint32 damage
= CalculateDamage (attType
, false);
2241 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2243 if (hitInfo
& HITINFO_MISS
)
2245 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2249 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2251 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2252 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2256 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2258 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2260 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2261 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2265 if (GetTypeId() == TYPEID_PLAYER
)
2266 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2267 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2269 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2270 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2272 // extra attack only at any non extra attack (normal case)
2273 if(!extra
&& extraAttacks
)
2275 while(m_extraAttacks
)
2277 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2278 if(m_extraAttacks
> 0)
2284 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2286 // Miss chance based on melee
2287 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2289 // Critical hit chance
2290 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2291 // this is to avoid compiler issue when declaring variables inside if
2292 float block_chance
, parry_chance
, dodge_chance
;
2294 // cannot be dodged/parried/blocked
2295 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2297 block_chance
= 0.0f
;
2298 parry_chance
= 0.0f
;
2299 dodge_chance
= 0.0f
;
2303 // parry can be avoided only by some abilities
2304 parry_chance
= pVictim
->GetUnitParryChance();
2305 // block might be bypassed by it as well
2306 block_chance
= pVictim
->GetUnitBlockChance();
2307 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2308 dodge_chance
= pVictim
->GetUnitDodgeChance();
2311 // Only players can have Talent&Spell bonuses
2312 if (GetTypeId() == TYPEID_PLAYER
)
2314 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2315 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2317 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents for speed
2319 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2320 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2322 // can't be dodged rogue finishing move
2323 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2325 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2327 dodge_chance
= 0.0f
;
2336 if(Player
* modOwner
= GetSpellModOwner())
2337 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2339 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2341 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);
2344 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2346 // This is only wrapper
2348 // Miss chance based on melee
2349 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2351 // Critical hit chance
2352 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2354 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2355 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2356 float block_chance
= pVictim
->GetUnitBlockChance();
2357 float parry_chance
= pVictim
->GetUnitParryChance();
2359 // Useful if want to specify crit & miss chances for melee, else it could be removed
2360 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2362 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);
2365 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
2367 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2368 return MELEE_HIT_EVADE
;
2370 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2371 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2373 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2374 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2376 // bonus from skills is 0.04%
2377 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2378 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2379 int32 sum
= 0, tmp
= 0;
2380 int32 roll
= urand (0, 10000);
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2383 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2384 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2388 if (tmp
> 0 && roll
< (sum
+= tmp
))
2390 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2391 return MELEE_HIT_MISS
;
2394 // always crit against a sitting target (except 0 crit chance)
2395 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2397 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2398 return MELEE_HIT_CRIT
;
2403 // only players can't dodge if attacker is behind
2404 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2406 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2410 // Reduce dodge chance by attacker expertise rating
2411 if (GetTypeId() == TYPEID_PLAYER
)
2412 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2414 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2415 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2418 if ( (tmp
> 0) // check if unit _can_ dodge
2419 && ((tmp
-= skillBonus
) > 0)
2420 && roll
< (sum
+= tmp
))
2422 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2423 return MELEE_HIT_DODGE
;
2427 // parry & block chances
2429 // check if attack comes from behind, nobody can parry or block if attacker is behind
2430 if (!pVictim
->HasInArc(M_PI
,this))
2432 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2436 // Reduce parry chance by attacker expertise rating
2437 if (GetTypeId() == TYPEID_PLAYER
)
2438 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2440 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2442 int32 tmp
= int32(parry_chance
);
2443 if ( (tmp
> 0) // check if unit _can_ parry
2444 && ((tmp
-= skillBonus
) > 0)
2445 && (roll
< (sum
+= tmp
)))
2447 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2448 return MELEE_HIT_PARRY
;
2452 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2455 if ( (tmp
> 0) // check if unit _can_ block
2456 && ((tmp
-= skillBonus
) > 0)
2457 && (roll
< (sum
+= tmp
)))
2460 tmp
= crit_chance
+ skillBonus2
;
2461 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2463 if ( roll_chance_i(tmp
/100))
2465 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2466 return MELEE_HIT_BLOCK_CRIT
;
2469 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2470 return MELEE_HIT_BLOCK
;
2476 tmp
= crit_chance
+ skillBonus2
;
2478 if (tmp
> 0 && roll
< (sum
+= tmp
))
2480 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2481 return MELEE_HIT_CRIT
;
2484 // 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)
2485 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2486 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2487 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2488 getLevel() < pVictim
->getLevelForTarget(this) )
2490 // cap possible value (with bonuses > max skill)
2491 int32 skill
= attackerWeaponSkill
;
2492 int32 maxskill
= attackerMaxSkillValueForLevel
;
2493 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2495 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2496 tmp
= tmp
> 4000 ? 4000 : tmp
;
2497 if (roll
< (sum
+= tmp
))
2499 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2500 return MELEE_HIT_GLANCING
;
2504 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2506 // mobs can score crushing blows if they're 3 or more levels above victim
2507 // or when their weapon skill is 15 or more above victim's defense skill
2508 tmp
= victimDefenseSkill
;
2509 int32 tmpmax
= victimMaxSkillValueForLevel
;
2510 // having defense above your maximum (from items, talents etc.) has no effect
2511 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2512 // tmp = mob's level * 5 - player's current defense skill
2513 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2516 // add 2% chance per lacking skill point, min. is 15%
2517 tmp
= tmp
* 200 - 1500;
2518 if (roll
< (sum
+= tmp
))
2520 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2521 return MELEE_HIT_CRUSHING
;
2526 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2527 return MELEE_HIT_NORMAL
;
2530 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2532 float min_damage
, max_damage
;
2534 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2535 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2541 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2542 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2545 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2546 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2549 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2550 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2552 // Just for good manner
2560 if (min_damage
> max_damage
)
2562 std::swap(min_damage
,max_damage
);
2565 if(max_damage
== 0.0f
)
2568 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2571 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2573 if(spellProto
->spellLevel
<= 0)
2576 float LvlPenalty
= 0.0f
;
2578 if(spellProto
->spellLevel
< 20)
2579 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2580 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2581 if(LvlFactor
> 1.0f
)
2584 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2587 void Unit::SendAttackStart(Unit
* pVictim
)
2589 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2590 data
<< uint64(GetGUID());
2591 data
<< uint64(pVictim
->GetGUID());
2593 SendMessageToSet(&data
, true);
2594 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2597 void Unit::SendAttackStop(Unit
* victim
)
2602 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2603 data
.append(GetPackGUID());
2604 data
.append(victim
->GetPackGUID()); // can be 0x00...
2605 data
<< uint32(0); // can be 0x1
2606 SendMessageToSet(&data
, true);
2607 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2609 /*if(victim->GetTypeId() == TYPEID_UNIT)
2610 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2614 // Melee based spells can be miss, parry or dodge on this step
2615 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2616 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2618 // Calculate hit chance (more correct for chance mod)
2621 // PvP - PvE melee chances
2622 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2623 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2625 HitChance = 95 - leveldif;
2627 HitChance = 93 - (leveldif - 2) * lchance;
2629 // Hit chance depends from victim auras
2630 if(attType == RANGED_ATTACK)
2631 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2633 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2635 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2636 if(Player *modOwner = GetSpellModOwner())
2637 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2640 float miss_chance= 100.0f - HitChance;
2642 // Bonuses from attacker aura and ratings
2643 if (attType == RANGED_ATTACK)
2644 miss_chance -= m_modRangedHitChance;
2646 miss_chance -= m_modMeleeHitChance;
2648 // bonus from skills is 0.04%
2649 miss_chance -= skillDiff * 0.04f;
2651 // Limit miss chance from 0 to 60%
2652 if (miss_chance < 0.0f)
2654 if (miss_chance > 60.0f)
2659 // Melee based spells hit result calculations
2660 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2662 WeaponAttackType attType = BASE_ATTACK;
2664 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2665 attType = RANGED_ATTACK;
2667 // bonus from skills is 0.04% per skill Diff
2668 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2669 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2670 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2672 uint32 roll = urand (0, 10000);
2673 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2676 uint32 tmp = missChance;
2678 return SPELL_MISS_MISS;
2680 // Same spells cannot be parry/dodge
2681 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2682 return SPELL_MISS_NONE;
2684 // Ranged attack can`t miss too
2685 if (attType == RANGED_ATTACK)
2686 return SPELL_MISS_NONE;
2688 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2691 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2692 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2693 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2695 // Reduce dodge chance by attacker expertise rating
2696 if (GetTypeId() == TYPEID_PLAYER)
2697 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2698 if (dodgeChance < 0)
2701 // Can`t dodge from behind in PvP (but its possible in PvE)
2702 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2705 // Rogue talent`s cant be dodged
2706 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2707 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2709 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2711 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2721 return SPELL_MISS_DODGE;
2724 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2725 // Reduce parry chance by attacker expertise rating
2726 if (GetTypeId() == TYPEID_PLAYER)
2727 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2728 // Can`t parry from behind
2729 if (parryChance < 0 || attackFromBehind)
2734 return SPELL_MISS_PARRY;
2736 return SPELL_MISS_NONE;
2739 // TODO need use unit spell resistances in calculations
2740 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2742 // Can`t miss on dead target (on skinning for example)
2743 if (!pVictim
->isAlive())
2744 return SPELL_MISS_NONE
;
2746 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2747 // PvP - PvE spell misschances per leveldif > 2
2748 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2749 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2751 // Base hit chance from attacker and victim levels
2754 modHitChance
= 96 - leveldif
;
2756 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2758 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2759 if(Player
*modOwner
= GetSpellModOwner())
2760 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2761 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2762 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2763 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2764 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2765 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2766 if (IsAreaOfEffectSpell(spell
))
2767 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2768 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2769 if (IsDispelSpell(spell
))
2770 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2771 // Chance resist mechanic (select max value from every mechanic spell effect)
2772 int32 resist_mech
= 0;
2773 // Get effects mechanic and chance
2774 for(int eff
= 0; eff
< 3; ++eff
)
2776 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2779 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2780 if (resist_mech
< temp
)
2785 modHitChance
-=resist_mech
;
2787 // Chance resist debuff
2788 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2790 int32 HitChance
= modHitChance
* 100;
2791 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2792 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2794 // Decrease hit chance from victim rating bonus
2795 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2796 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2798 if (HitChance
< 100) HitChance
= 100;
2799 if (HitChance
> 9900) HitChance
= 9900;
2801 uint32 rand
= urand(0,10000);
2802 if (rand
> HitChance
)
2803 return SPELL_MISS_RESIST
;
2804 return SPELL_MISS_NONE
;
2807 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2809 // Return evade for units in evade mode
2810 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2811 return SPELL_MISS_EVADE
;
2813 // Check for immune (use charges)
2814 if (pVictim
->IsImmunedToSpell(spell
,true))
2815 return SPELL_MISS_IMMUNE
;
2817 // All positive spells can`t miss
2818 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2819 if (IsPositiveSpell(spell
->Id
))
2820 return SPELL_MISS_NONE
;
2822 // Check for immune (use charges)
2823 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2824 return SPELL_MISS_IMMUNE
;
2826 // Try victim reflect spell
2829 // specialized first
2830 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2831 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2833 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2835 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2836 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2838 if((*i
)->m_procCharges
> 0)
2840 --(*i
)->m_procCharges
;
2841 if((*i
)->m_procCharges
==0)
2842 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2844 return SPELL_MISS_REFLECT
;
2849 // generic reflection
2850 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2851 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2853 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2854 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2856 if((*i
)->m_procCharges
> 0)
2858 --(*i
)->m_procCharges
;
2859 if((*i
)->m_procCharges
==0)
2860 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2862 return SPELL_MISS_REFLECT
;
2867 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2868 for (int i
=0;i
<3;i
++)
2870 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2871 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2872 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2873 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2874 return SPELL_MISS_NONE
;
2877 // TODO need use this code for spell hit result calculation
2878 // now code commented for computability
2879 switch (spell
->DmgClass
)
2881 case SPELL_DAMAGE_CLASS_RANGED
:
2882 case SPELL_DAMAGE_CLASS_MELEE
:
2883 // return MeleeSpellHitResult(pVictim, spell);
2884 return SPELL_MISS_NONE
;
2885 case SPELL_DAMAGE_CLASS_NONE
:
2886 case SPELL_DAMAGE_CLASS_MAGIC
:
2887 return MagicSpellHitResult(pVictim
, spell
);
2889 return SPELL_MISS_NONE
;
2892 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2897 // Base misschance 5%
2898 float misschance
= 5.0f
;
2900 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2901 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2903 bool isNormal
= false;
2904 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2906 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2912 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2922 // PvP : PvE melee misschances per leveldif > 2
2923 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2925 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2929 // Hit chance from attacker based on ratings and auras
2930 float m_modHitChance
;
2931 if (attType
== RANGED_ATTACK
)
2932 m_modHitChance
= m_modRangedHitChance
;
2934 m_modHitChance
= m_modMeleeHitChance
;
2937 misschance
+= (leveldif
- m_modHitChance
);
2939 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2941 // Hit chance for victim based on ratings
2942 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2944 if (attType
== RANGED_ATTACK
)
2945 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2947 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2950 // Modify miss chance by victim auras
2951 if(attType
== RANGED_ATTACK
)
2952 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2954 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2956 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2957 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2958 misschance
-= skillBonus
* 0.04f
;
2960 // Limit miss chance from 0 to 60%
2961 if ( misschance
< 0.0f
)
2963 if ( misschance
> 60.0f
)
2969 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2971 if(GetTypeId() == TYPEID_PLAYER
)
2973 // in PvP use full skill instead current skill value
2974 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2975 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2976 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2977 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2981 return GetUnitMeleeSkill(target
);
2984 float Unit::GetUnitDodgeChance() const
2986 if(hasUnitState(UNIT_STAT_STUNNED
))
2988 if( GetTypeId() == TYPEID_PLAYER
)
2989 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2992 if(((Creature
const*)this)->isTotem())
2997 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2998 return dodge
> 0.0f
? dodge
: 0.0f
;
3003 float Unit::GetUnitParryChance() const
3005 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3008 float chance
= 0.0f
;
3010 if(GetTypeId() == TYPEID_PLAYER
)
3012 Player
const* player
= (Player
const*)this;
3013 if(player
->CanParry() )
3015 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3017 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3020 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3023 else if(GetTypeId() == TYPEID_UNIT
)
3025 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3028 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3032 return chance
> 0.0f
? chance
: 0.0f
;
3035 float Unit::GetUnitBlockChance() const
3037 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3040 if(GetTypeId() == TYPEID_PLAYER
)
3042 Player
const* player
= (Player
const*)this;
3043 if(player
->CanBlock() )
3045 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3046 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3047 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3049 // is player but has no block ability or no not broken shield equipped
3054 if(((Creature
const*)this)->isTotem())
3059 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3060 return block
> 0.0f
? block
: 0.0f
;
3065 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3069 if(GetTypeId() == TYPEID_PLAYER
)
3074 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3077 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3080 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3082 // Just for good manner
3091 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3095 if(attackType
== RANGED_ATTACK
)
3096 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3098 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3100 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3102 // reduce crit chance from Rating for players
3103 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3105 if (attackType
==RANGED_ATTACK
)
3106 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3108 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3116 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3119 if(GetTypeId() == TYPEID_PLAYER
)
3121 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3123 // feral or unarmed skill only for base attack
3124 if(attType
!= BASE_ATTACK
&& !item
)
3127 if(((Player
*)this)->IsInFeralForm())
3128 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3130 // weapon skill or (unarmed for base attack)
3131 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3133 // in PvP use full skill instead current skill value
3134 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3135 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3136 : ((Player
*)this)->GetSkillValue(skill
);
3137 // Modify value from ratings
3138 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3141 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3142 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3143 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3147 value
= GetUnitMeleeSkill(target
);
3151 void Unit::_UpdateSpells( uint32 time
)
3153 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3154 _UpdateAutoRepeatSpell();
3156 // remove finished spells from current pointers
3157 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3159 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3161 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3162 m_currentSpells
[i
] = NULL
; // remove pointer
3166 // TODO: Find a better way to prevent crash when multiple auras are removed.
3168 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3170 (*i
).second
->SetUpdated(false);
3172 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3178 // prevent double update
3179 if ((*i
).second
->IsUpdated())
3181 (*i
).second
->SetUpdated(true);
3182 (*i
).second
->Update( time
);
3183 // several auras can be deleted due to update
3186 if (m_Auras
.empty()) break;
3187 next
= m_Auras
.begin();
3193 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3197 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3212 if(!m_gameObj
.empty())
3214 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3215 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3218 //(*i)->Update( difftime );
3219 if( !(*ite1
)->isSpawned() )
3221 (*ite1
)->SetOwnerGUID(0);
3222 (*ite1
)->SetRespawnTime(0);
3224 dnext1
= m_gameObj
.erase(ite1
);
3232 void Unit::_UpdateAutoRepeatSpell()
3234 //check "realtime" interrupts
3235 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3237 // cancel wand shoot
3238 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3239 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3240 m_AutoRepeatFirstCast
= true;
3245 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3246 setAttackTimer(RANGED_ATTACK
,500);
3247 m_AutoRepeatFirstCast
= false;
3250 if (isAttackReady(RANGED_ATTACK
))
3252 // Check if able to cast
3253 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3255 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3260 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3261 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3263 // all went good, reset attack
3264 resetAttackTimer(RANGED_ATTACK
);
3268 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3270 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3272 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3274 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3276 // break same type spell if it is not delayed
3277 InterruptSpell(CSpellType
,false);
3279 // special breakage effects:
3282 case CURRENT_GENERIC_SPELL
:
3284 // generic spells always break channeled not delayed spells
3285 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3287 // autorepeat breaking
3288 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3290 // break autorepeat if not Auto Shot
3291 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3292 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3293 m_AutoRepeatFirstCast
= true;
3297 case CURRENT_CHANNELED_SPELL
:
3299 // channel spells always break generic non-delayed and any channeled spells
3300 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3301 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3303 // it also does break autorepeat if not Auto Shot
3304 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3305 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3306 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3309 case CURRENT_AUTOREPEAT_SPELL
:
3311 // only Auto Shoot does not break anything
3312 if (pSpell
->m_spellInfo
->Category
== 351)
3314 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3315 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3316 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3318 // special action: set first cast flag
3319 m_AutoRepeatFirstCast
= true;
3324 // other spell types don't break anything now
3328 // current spell (if it is still here) may be safely deleted now
3329 if (m_currentSpells
[CSpellType
])
3330 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3332 // set new current spell
3333 m_currentSpells
[CSpellType
] = pSpell
;
3334 pSpell
->SetReferencedFromCurrent(true);
3337 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3339 assert(spellType
< CURRENT_MAX_SPELL
);
3341 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3343 // send autorepeat cancel message for autorepeat spells
3344 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3346 if(GetTypeId()==TYPEID_PLAYER
)
3347 ((Player
*)this)->SendAutoRepeatCancel();
3350 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3351 m_currentSpells
[spellType
]->cancel();
3352 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3353 m_currentSpells
[spellType
] = NULL
;
3357 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3359 // We don't do loop here to explicitly show that melee spell is excluded.
3360 // Maybe later some special spells will be excluded too.
3362 // generic spells are casted when they are not finished and not delayed
3363 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3364 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3365 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3368 // channeled spells may be delayed, but they are still considered casted
3369 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3370 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3373 // autorepeat spells may be finished or delayed, but they are still considered casted
3374 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3380 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3382 // generic spells are interrupted if they are not finished or delayed
3383 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3385 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3386 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3387 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3388 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3389 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3392 // autorepeat spells are interrupted if they are not finished or delayed
3393 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3395 // send disable autorepeat packet in any case
3396 if(GetTypeId()==TYPEID_PLAYER
)
3397 ((Player
*)this)->SendAutoRepeatCancel();
3399 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3400 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3401 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3402 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3403 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3406 // channeled spells are interrupted if they are not finished, even if they are delayed
3407 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3409 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3410 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3411 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3412 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3416 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3418 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3419 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3420 return m_currentSpells
[i
];
3424 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3426 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3429 void Unit::SetInFront(Unit
const* target
)
3431 SetOrientation(GetAngle(target
));
3434 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3436 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3439 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3442 return c
->canSwim();
3444 return c
->canWalk() || c
->canFly();
3447 bool Unit::IsInWater() const
3449 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3452 bool Unit::IsUnderWater() const
3454 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3457 void Unit::DeMorph()
3459 SetDisplayId(GetNativeDisplayId());
3462 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3466 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3467 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3468 modifier
+= (*i
)->GetModifier()->m_amount
;
3473 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3475 float multiplier
= 1.0f
;
3477 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3478 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3479 multiplier
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3484 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3488 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3489 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3490 if ((*i
)->GetModifier()->m_amount
> modifier
)
3491 modifier
= (*i
)->GetModifier()->m_amount
;
3496 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3500 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3501 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3502 if ((*i
)->GetModifier()->m_amount
< modifier
)
3503 modifier
= (*i
)->GetModifier()->m_amount
;
3508 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3512 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3513 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3515 Modifier
* mod
= (*i
)->GetModifier();
3516 if (mod
->m_miscvalue
& misc_mask
)
3517 modifier
+= mod
->m_amount
;
3522 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3524 float multiplier
= 1.0f
;
3526 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3527 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3529 Modifier
* mod
= (*i
)->GetModifier();
3530 if (mod
->m_miscvalue
& misc_mask
)
3531 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3536 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3540 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3541 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3543 Modifier
* mod
= (*i
)->GetModifier();
3544 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3545 modifier
= mod
->m_amount
;
3551 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3555 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3556 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3558 Modifier
* mod
= (*i
)->GetModifier();
3559 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3560 modifier
= mod
->m_amount
;
3566 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3570 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3571 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3573 Modifier
* mod
= (*i
)->GetModifier();
3574 if (mod
->m_miscvalue
== misc_value
)
3575 modifier
+= mod
->m_amount
;
3580 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3582 float multiplier
= 1.0f
;
3584 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3585 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3587 Modifier
* mod
= (*i
)->GetModifier();
3588 if (mod
->m_miscvalue
== misc_value
)
3589 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3594 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3598 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3599 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3601 Modifier
* mod
= (*i
)->GetModifier();
3602 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3603 modifier
= mod
->m_amount
;
3609 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3613 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3614 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3616 Modifier
* mod
= (*i
)->GetModifier();
3617 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3618 modifier
= mod
->m_amount
;
3624 bool Unit::AddAura(Aura
*Aur
)
3626 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3627 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3628 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3634 if(Aur
->GetTarget() != this)
3636 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3637 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3638 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3643 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3645 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3646 AuraMap::iterator i
= m_Auras
.find( spair
);
3648 // take out same spell
3649 if (i
!= m_Auras
.end())
3651 // passive and persistent auras can stack with themselves any number of times
3652 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3654 // replace aura if next will > spell StackAmount
3655 if(aurSpellInfo
->StackAmount
)
3657 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3658 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3660 // if StackAmount==0 not allow auras from same caster
3663 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3665 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3667 // can be only single (this check done at _each_ aura add
3668 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3673 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3676 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3677 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3678 case SPELL_AURA_PERIODIC_LEECH
:
3679 case SPELL_AURA_PERIODIC_HEAL
:
3680 case SPELL_AURA_OBS_MOD_HEALTH
:
3681 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3682 case SPELL_AURA_PERIODIC_ENERGIZE
:
3683 case SPELL_AURA_OBS_MOD_MANA
:
3684 case SPELL_AURA_POWER_BURN_MANA
:
3686 default: // not allow
3687 // can be only single (this check done at _each_ aura add
3688 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3700 // passive auras stack with all (except passive spell proc auras)
3701 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3702 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3704 if (!RemoveNoStackAurasDueToAura(Aur
))
3707 return false; // couldn't remove conflicting aura with higher rank
3711 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3712 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3714 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3717 Unit
* caster
= Aur
->GetCaster();
3718 if(!caster
) // caster deleted and not required adding scAura
3721 bool restart
= false;
3722 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3723 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3725 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3726 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3728 if ((*itr
)->IsInUse())
3730 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());
3733 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3742 scAuras
.push_back(Aur
);
3748 // add aura, register in lists and arrays
3750 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3751 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3753 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3756 Aur
->ApplyModifier(true,true);
3757 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3761 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3763 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3766 AuraMap::iterator i
,next
;
3767 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3771 uint32 i_spellId
= (*i
).second
->GetId();
3772 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3774 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3776 RemoveAurasDueToSpell(i_spellId
);
3778 if( m_Auras
.empty() )
3781 next
= m_Auras
.begin();
3787 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3792 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3796 uint32 spellId
= Aur
->GetId();
3797 uint32 effIndex
= Aur
->GetEffIndex();
3799 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3801 AuraMap::iterator i
,next
;
3802 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3806 if (!(*i
).second
) continue;
3808 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3813 uint32 i_spellId
= i_spellProto
->Id
;
3815 if(IsPassiveSpell(i_spellId
))
3817 if(IsPassiveStackableSpell(i_spellId
))
3820 // passive non-stackable spells not stackable only with another rank of same spell
3821 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3825 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3827 if(i_spellId
== spellId
) continue;
3829 bool is_triggered_by_spell
= false;
3830 // prevent triggered aura of removing aura that triggered it
3831 for(int j
= 0; j
< 3; ++j
)
3832 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3833 is_triggered_by_spell
= true;
3834 if (is_triggered_by_spell
) continue;
3836 for(int j
= 0; j
< 3; ++j
)
3838 // prevent remove dummy triggered spells at next effect aura add
3839 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggered spell
3841 case SPELL_EFFECT_DUMMY
:
3844 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3849 if(is_triggered_by_spell
)
3852 // prevent remove form main spell by triggered passive spells
3853 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3855 case SPELL_AURA_MOD_SHAPESHIFT
:
3858 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3859 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3860 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3866 if(!is_triggered_by_spell
)
3868 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3870 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3872 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3874 // cannot remove higher rank
3875 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3876 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3879 // Its a parent aura (create this aura in ApplyModifier)
3880 if ((*i
).second
->IsInUse())
3882 sLog
.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i
->second
->GetId(), i
->second
->GetEffIndex(),Aur
->GetId(), Aur
->GetEffIndex());
3885 RemoveAurasDueToSpell(i_spellId
);
3887 if( m_Auras
.empty() )
3890 next
= m_Auras
.begin();
3892 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3894 // Its a parent aura (create this aura in ApplyModifier)
3895 if ((*i
).second
->IsInUse())
3897 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());
3900 RemoveAurasDueToSpell(i_spellId
);
3902 if( m_Auras
.empty() )
3905 next
= m_Auras
.begin();
3907 // Potions stack aura by aura (elixirs/flask already checked)
3908 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3910 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3912 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3913 return false; // cannot remove higher rank
3915 // Its a parent aura (create this aura in ApplyModifier)
3916 if ((*i
).second
->IsInUse())
3918 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());
3930 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3932 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3933 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3935 if(iter
->second
!=except
)
3938 iter
= m_Auras
.lower_bound(spair
);
3945 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3947 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3949 Aura
*aur
= iter
->second
;
3950 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3952 // Custom dispel case
3953 // Unstable Affliction
3954 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3956 int32 damage
= aur
->GetModifier()->m_amount
*9;
3957 uint64 caster_guid
= aur
->GetCasterGUID();
3960 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3962 // backfire damage and silence
3963 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3965 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3968 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3975 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3977 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3979 Aura
*aur
= iter
->second
;
3980 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3982 int32 basePoints
= aur
->GetBasePoints();
3983 // construct the new aura for the attacker
3984 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3988 // set its duration and maximum duration
3989 // max duration 2 minutes (in msecs)
3990 int32 dur
= aur
->GetAuraDuration();
3991 const int32 max_dur
= 2*MINUTE
*1000;
3992 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3993 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3995 // add the new aura to stealer
3996 stealer
->AddAura(new_aur
);
3998 // Remove aura as dispel
3999 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
4006 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4008 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4010 if (iter
->second
->GetId() == spellId
)
4011 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4017 void Unit::RemoveAurasWithDispelType( DispelType type
)
4019 // Create dispel mask by dispel type
4020 uint32 dispelMask
= GetDispellMask(type
);
4021 // Dispel all existing auras vs current dispel type
4022 AuraMap
& auras
= GetAuras();
4023 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4025 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4026 if( (1<<spell
->Dispel
) & dispelMask
)
4029 RemoveAurasDueToSpell(spell
->Id
);
4030 itr
= auras
.begin();
4037 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4039 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4040 if(iter
!= m_Auras
.end())
4044 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4046 for (int i
= 0; i
< 3; ++i
)
4047 RemoveAura(spellId
,i
,except
);
4050 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4052 for (int k
=0; k
< 3; ++k
)
4054 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4055 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4057 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4060 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4068 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4070 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4072 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4079 void Unit::RemoveNotOwnSingleTargetAuras()
4081 // single target auras from other casters
4082 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4084 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4090 // single target auras at other targets
4091 AuraList
& scAuras
= GetSingleCastAuras();
4092 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4095 if (aura
->GetTarget()!=this)
4097 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4098 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4099 iter
= scAuras
.begin();
4107 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4109 Aura
* Aur
= i
->second
;
4110 SpellEntry
const* AurSpellInfo
= Aur
->GetSpellProto();
4112 Unit
* caster
= NULL
;
4113 if (IsSingleTargetSpell(AurSpellInfo
))
4115 caster
= Aur
->GetCaster();
4118 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4119 scAuras
.remove(Aur
);
4123 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4128 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4129 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4131 m_modAuras
[Aur
->GetModifier()->m_auraname
].remove(Aur
);
4135 Aur
->SetRemoveMode(mode
);
4136 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4137 // remove aura from list before to prevent deleting it before
4139 ++m_removedAuras
; // internal count used by unit update
4141 // Statue unsummoned at aura remove
4142 Totem
* statue
= NULL
;
4143 bool caster_channeled
= false;
4144 if(IsChanneledSpell(AurSpellInfo
))
4146 if(!caster
) // can be already located for IsSingleTargetSpell case
4147 caster
= Aur
->GetCaster();
4151 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4152 statue
= ((Totem
*)caster
);
4154 caster_channeled
= caster
==this;
4158 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4159 Aur
->ApplyModifier(false,true);
4163 if(caster_channeled
)
4164 RemoveAurasAtChanneledTarget (AurSpellInfo
);
4169 // only way correctly remove all auras from list
4170 if( m_Auras
.empty() )
4173 i
= m_Auras
.begin();
4176 void Unit::RemoveAllAuras()
4178 while (!m_Auras
.empty())
4180 AuraMap::iterator iter
= m_Auras
.begin();
4185 void Unit::RemoveAllAurasOnDeath()
4187 // used just after dieing to remove all visible auras
4188 // and disable the mods for the passive ones
4189 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4191 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4192 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4198 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4200 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4201 if (iter
!= m_Auras
.end())
4203 if (iter
->second
->GetAuraDuration() < delaytime
)
4204 iter
->second
->SetAuraDuration(0);
4206 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4207 iter
->second
->SendAuraUpdate(false);
4208 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4212 void Unit::_RemoveAllAuraMods()
4214 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4216 (*i
).second
->ApplyModifier(false);
4220 void Unit::_ApplyAllAuraMods()
4222 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4224 (*i
).second
->ApplyModifier(true);
4228 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4230 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4231 if (iter
!= m_Auras
.end())
4232 return iter
->second
;
4236 void Unit::AddDynObject(DynamicObject
* dynObj
)
4238 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4241 void Unit::RemoveDynObject(uint32 spellid
)
4243 if(m_dynObjGUIDs
.empty())
4245 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4247 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4250 i
= m_dynObjGUIDs
.erase(i
);
4252 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4255 i
= m_dynObjGUIDs
.erase(i
);
4262 void Unit::RemoveAllDynObjects()
4264 while(!m_dynObjGUIDs
.empty())
4266 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4269 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4273 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
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
&& dynObj
->GetEffIndex() == effIndex
)
4291 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4293 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4295 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4298 i
= m_dynObjGUIDs
.erase(i
);
4302 if (dynObj
->GetSpellId() == spellId
)
4309 void Unit::AddGameObject(GameObject
* gameObj
)
4311 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4312 m_gameObj
.push_back(gameObj
);
4313 gameObj
->SetOwnerGUID(GetGUID());
4316 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4318 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4320 // GO created by some spell
4321 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4323 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4324 // Need activate spell use for owner
4325 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4326 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4328 gameObj
->SetOwnerGUID(0);
4329 m_gameObj
.remove(gameObj
);
4332 gameObj
->SetRespawnTime(0);
4337 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4339 if(m_gameObj
.empty())
4341 std::list
<GameObject
*>::iterator i
, next
;
4342 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4345 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4347 (*i
)->SetOwnerGUID(0);
4350 (*i
)->SetRespawnTime(0);
4354 next
= m_gameObj
.erase(i
);
4361 void Unit::RemoveAllGameObjects()
4363 // remove references to unit
4364 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4366 (*i
)->SetOwnerGUID(0);
4367 (*i
)->SetRespawnTime(0);
4369 i
= m_gameObj
.erase(i
);
4373 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4375 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4376 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4377 data
.append(target
->GetPackGUID());
4378 data
.append(GetPackGUID());
4379 data
<< uint32(SpellID
);
4380 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4381 data
<< uint32(0); // wotlk
4382 data
<< uint8(damageSchoolMask
); // spell school
4383 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4384 data
<< uint32(Resist
); // resist
4385 data
<< uint8(PhysicalDamage
); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
4386 data
<< uint8(0); // unk isFromAura
4387 data
<< uint32(Blocked
); // blocked
4388 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4389 data
<< uint8(0); // isDebug?
4390 SendMessageToSet( &data
, true );
4393 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4395 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4396 data
<< uint32(spellID
);
4397 data
<< uint64(GetGUID());
4398 data
<< uint8(0); // can be 0 or 1
4399 data
<< uint32(1); // target count
4400 // for(i = 0; i < target count; ++i)
4401 data
<< uint64(target
->GetGUID()); // target GUID
4402 data
<< uint8(missInfo
);
4404 SendMessageToSet(&data
, true);
4407 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4409 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4411 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4412 data
<< uint32(HitInfo
); // flags
4413 data
.append(GetPackGUID());
4414 data
.append(target
->GetPackGUID());
4415 data
<< uint32(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);// damage
4416 data
<< uint32(0); // overkill value
4418 data
<< (uint8
)SwingType
; // count?
4420 // for(i = 0; i < SwingType; ++i)
4421 data
<< (uint32
)damageSchoolMask
;
4422 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4423 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4426 if(HitInfo
& (HITINFO_ABSORB
| HITINFO_ABSORB2
))
4428 // for(i = 0; i < SwingType; ++i)
4429 data
<< uint32(AbsorbDamage
);
4433 if(HitInfo
& (HITINFO_RESIST
| HITINFO_RESIST2
))
4435 // for(i = 0; i < SwingType; ++i)
4436 data
<< uint32(Resist
);
4440 data
<< (uint8
)TargetState
;
4444 if(HitInfo
& HITINFO_BLOCK
)
4446 data
<< uint32(BlockedAmount
);
4449 if(HitInfo
& HITINFO_UNK3
)
4454 if(HitInfo
& HITINFO_UNK1
)
4465 for(uint8 i
= 0; i
< 5; ++i
)
4473 SendMessageToSet( &data
, true );
4476 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4478 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4480 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4482 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4483 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4484 // That is the question though if it's fully correct
4485 if(procSpell
&& !isTriggeredSpell
)
4487 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4489 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4490 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4491 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4492 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4493 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4495 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4497 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4498 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4499 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4500 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4501 attType
= RANGED_ATTACK
;
4504 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4505 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4507 // Not much to do if no flags are set.
4510 // 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
4511 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4512 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4515 // Now go on with a victim's events'n'auras
4516 // Not much to do if no flags are set or there is no victim
4517 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4519 // 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
4520 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4521 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4525 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4530 uint32 procAttacker
= PROC_FLAG_NONE
;
4531 uint32 procVictim
= PROC_FLAG_NONE
;
4535 case MELEE_HIT_EVADE
:
4537 case MELEE_HIT_MISS
:
4538 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4540 procAttacker
= PROC_FLAG_MISS
;
4543 case MELEE_HIT_BLOCK_CRIT
:
4544 case MELEE_HIT_CRIT
:
4545 if(spellCasted
&& attType
== BASE_ATTACK
)
4547 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4548 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4549 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4551 procVictim
|= PROC_FLAG_BLOCK
;
4552 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4555 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4557 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4558 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4562 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4563 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4566 case MELEE_HIT_PARRY
:
4567 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4568 procVictim
= PROC_FLAG_PARRY
;
4570 case MELEE_HIT_BLOCK
:
4571 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4572 procVictim
= PROC_FLAG_BLOCK
;
4574 case MELEE_HIT_DODGE
:
4575 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4576 procVictim
= PROC_FLAG_DODGE
;
4578 case MELEE_HIT_CRUSHING
:
4579 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4581 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4582 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4586 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4587 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4591 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4593 procAttacker
= PROC_FLAG_HIT_MELEE
;
4594 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4598 procAttacker
= PROC_FLAG_HIT_RANGED
;
4599 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4605 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4607 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4608 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4611 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4613 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4615 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4616 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4618 uint32 triggered_spell_id
= 0;
4619 Unit
* target
= pVictim
;
4620 int32 basepoints0
= 0;
4622 switch(hasteSpell
->SpellFamilyName
)
4624 case SPELLFAMILY_ROGUE
:
4626 switch(hasteSpell
->Id
)
4632 target
= SelectNearbyTarget();
4635 basepoints0
= damage
;
4636 triggered_spell_id
= 22482;
4644 // processed charge only counting case
4645 if(!triggered_spell_id
)
4648 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4652 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4657 if(!target
|| target
!=this && !target
->isAlive())
4660 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4664 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4666 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4668 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4669 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4674 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4676 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4677 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4679 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4680 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4682 uint32 triggered_spell_id
= 0;
4683 Unit
* target
= pVictim
;
4684 int32 basepoints0
= 0;
4686 switch(dummySpell
->SpellFamilyName
)
4688 case SPELLFAMILY_GENERIC
:
4690 switch (dummySpell
->Id
)
4696 // prevent damage back from weapon special attacks
4697 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4700 // return damage % to attacker but < 50% own total health
4701 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4702 if(basepoints0
> GetMaxHealth()/2)
4703 basepoints0
= GetMaxHealth()/2;
4705 triggered_spell_id
= 25997;
4713 // prevent chain of triggered spell from same triggered spell
4714 if(procSpell
&& procSpell
->Id
==26654)
4717 target
= SelectNearbyTarget();
4721 triggered_spell_id
= 26654;
4727 if (!procSpell
|| procSpell
->Id
== 24659)
4729 // Need remove one 24659 aura
4730 RemoveSingleAuraFromStack(24659, 0);
4731 RemoveSingleAuraFromStack(24659, 1);
4734 // Restless Strength
4737 // Need remove one 24662 aura
4738 RemoveSingleAuraFromStack(24662, 0);
4741 // Adaptive Warding (Frostfire Regalia set)
4749 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4750 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4752 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4754 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4764 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4766 case SPELL_SCHOOL_NORMAL
:
4767 case SPELL_SCHOOL_HOLY
:
4768 return false; // ignored
4769 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4770 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4771 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4772 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4773 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4781 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4789 for(int j
= 0; j
< 3; ++j
)
4791 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4800 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4802 case SPELL_SCHOOL_NORMAL
:
4803 return false; // ignore
4804 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4805 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4806 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4807 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4808 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4809 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4817 // Mana Leech (Passive) (Priest Pet Aura)
4821 target
= GetOwner();
4825 basepoints0
= int32(damage
* 2.5f
); // manaregen
4826 triggered_spell_id
= 34650;
4832 // Cast finish spell at last charge
4833 if (triggeredByAura
->m_procCharges
> 1)
4837 triggered_spell_id
= 33494;
4840 // Twisted Reflection (boss spell)
4842 triggered_spell_id
= 21064;
4844 // Vampiric Aura (boss spell)
4847 basepoints0
= 3 * damage
; // 300%
4848 if (basepoints0
< 0)
4851 triggered_spell_id
= 31285;
4855 // Aura of Madness (Darkmoon Card: Madness trinket)
4856 //=====================================================
4857 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4858 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4859 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4860 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4861 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4862 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4863 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4864 // 41011 Martyr Complex: +35 stamina (All classes)
4865 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4866 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4869 if(GetTypeId() != TYPEID_PLAYER
)
4872 // Select class defined buff
4875 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4876 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4878 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4879 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4882 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4883 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4885 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4886 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4889 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4890 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4891 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4892 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4894 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4895 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4898 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4900 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4901 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4909 if (roll_chance_i(10))
4910 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4914 // TODO: need find item for aura and triggered spells
4915 // Sunwell Exalted Caster Neck (??? neck)
4916 // cast ??? Light's Wrath if Exalted by Aldor
4917 // cast ??? Arcane Bolt if Exalted by Scryers*/
4919 return false; // disable for while
4922 if(GetTypeId() != TYPEID_PLAYER)
4925 // Get Aldor reputation rank
4926 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4929 triggered_spell_id = ???
4932 // Get Scryers reputation rank
4933 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4935 triggered_spell_id = ???
4940 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4941 // cast 45479 Light's Wrath if Exalted by Aldor
4942 // cast 45429 Arcane Bolt if Exalted by Scryers
4945 if(GetTypeId() != TYPEID_PLAYER
)
4948 // Get Aldor reputation rank
4949 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4952 triggered_spell_id
= 45479;
4955 // Get Scryers reputation rank
4956 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4958 triggered_spell_id
= 45429;
4963 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4964 // cast 45480 Light's Strength if Exalted by Aldor
4965 // cast 45428 Arcane Strike if Exalted by Scryers
4968 if(GetTypeId() != TYPEID_PLAYER
)
4971 // Get Aldor reputation rank
4972 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4975 triggered_spell_id
= 45480;
4978 // Get Scryers reputation rank
4979 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4981 triggered_spell_id
= 45428;
4986 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4987 // cast 45431 Arcane Insight if Exalted by Aldor
4988 // cast 45432 Light's Ward if Exalted by Scryers
4991 if(GetTypeId() != TYPEID_PLAYER
)
4994 // Get Aldor reputation rank
4995 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4998 triggered_spell_id
= 45432;
5001 // Get Scryers reputation rank
5002 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5005 triggered_spell_id
= 45431;
5010 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
5011 // cast 45478 Light's Salvation if Exalted by Aldor
5012 // cast 45430 Arcane Surge if Exalted by Scryers
5015 if(GetTypeId() != TYPEID_PLAYER
)
5018 // Get Aldor reputation rank
5019 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
5022 triggered_spell_id
= 45478;
5025 // Get Scryers reputation rank
5026 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5028 triggered_spell_id
= 45430;
5036 case SPELLFAMILY_MAGE
:
5039 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5041 if (getPowerType() != POWER_MANA
)
5045 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5047 triggered_spell_id
= 29442;
5050 // Master of Elements
5051 if (dummySpell
->SpellIconID
== 1920)
5057 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5058 if( basepoints0
<=0 )
5062 triggered_spell_id
= 29077;
5065 switch(dummySpell
->Id
)
5074 switch (dummySpell
->Id
)
5076 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5077 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5078 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5079 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5080 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5082 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5086 triggered_spell_id
= 12654;
5092 //last charge and crit
5093 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5095 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5096 return true; // charge counting (will removed)
5099 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5100 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5105 case SPELLFAMILY_WARRIOR
:
5108 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5110 // check attack comes not from behind
5111 if (!HasInArc(M_PI
, pVictim
))
5114 triggered_spell_id
= 22858;
5119 case SPELLFAMILY_WARLOCK
:
5121 // Seed of Corruption
5122 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5124 Modifier
* mod
= triggeredByAura
->GetModifier();
5125 // if damage is more than need or target die from damage deal finish spell
5126 // FIX ME: not triggered currently at death
5127 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5129 // remember guid before aura delete
5130 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5132 // Remove aura (before cast for prevent infinite loop handlers)
5133 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5135 // Cast finish spell (triggeredByAura already not exist!)
5136 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5137 return true; // no hidden cooldown
5141 mod
->m_amount
-=damage
;
5144 // Seed of Corruption (Mobs cast) - no die req
5145 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5147 Modifier
* mod
= triggeredByAura
->GetModifier();
5148 // if damage is more than need deal finish spell
5149 if( mod
->m_amount
<= damage
)
5151 // remember guid before aura delete
5152 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5154 // Remove aura (before cast for prevent infinite loop handlers)
5155 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5157 // Cast finish spell (triggeredByAura already not exist!)
5158 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5159 return true; // no hidden cooldown
5162 mod
->m_amount
-=damage
;
5165 switch(dummySpell
->Id
)
5172 triggered_spell_id
= 17941;
5181 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5183 triggered_spell_id
= 30294;
5186 // Shadowflame (Voidheart Raiment set bonus)
5189 triggered_spell_id
= 37379;
5192 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5200 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5201 triggered_spell_id
= 37382;
5204 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5207 triggered_spell_id
= 37378;
5213 case SPELLFAMILY_PRIEST
:
5216 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5218 if(!pVictim
|| !pVictim
->isAlive())
5221 // pVictim is caster of aura
5222 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5226 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5227 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5228 return true; // no hidden cooldown
5230 switch(dummySpell
->Id
)
5235 if(!pVictim
|| !pVictim
->isAlive())
5238 // pVictim is caster of aura
5239 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5243 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5244 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5245 return true; // no hidden cooldown
5247 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5250 // Shadow Word: Pain
5251 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5252 triggered_spell_id
= 40441;
5254 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5255 triggered_spell_id
= 40440;
5262 // Oracle Healing Bonus ("Garments of the Oracle" set)
5266 basepoints0
= int32(damage
* 10/100);
5268 triggered_spell_id
= 26170;
5271 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5274 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5278 basepoints0
= int32(damage
* 2 / 100);
5280 triggered_spell_id
= 39373;
5283 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5286 triggered_spell_id
= 28810;
5292 case SPELLFAMILY_DRUID
:
5294 switch(dummySpell
->Id
)
5296 // Healing Touch (Dreamwalker Raiment set)
5300 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5302 triggered_spell_id
= 28742;
5305 // Healing Touch Refund (Idol of Longevity trinket)
5309 triggered_spell_id
= 28848;
5312 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5317 triggered_spell_id
= 37238;
5320 // Druid Tier 6 Trinket
5326 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5328 triggered_spell_id
= 40445;
5332 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5334 triggered_spell_id
= 40446;
5337 // Mangle (cat/bear)
5338 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5340 triggered_spell_id
= 40452;
5346 if (!roll_chance_f(chance
))
5355 // Deadly Interrupt Effect
5356 triggered_spell_id
= 32747;
5362 case SPELLFAMILY_ROGUE
:
5364 switch(dummySpell
->Id
)
5366 // Deadly Throw Interrupt
5369 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5373 triggered_spell_id
= 32747;
5378 if( dummySpell
->SpellIconID
== 2116 )
5383 // only rogue's finishing moves (maybe need additional checks)
5384 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5385 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5389 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5390 if(basepoints0
<= 0)
5394 triggered_spell_id
= 31663;
5399 case SPELLFAMILY_HUNTER
:
5401 // Thrill of the Hunt
5402 if ( dummySpell
->SpellIconID
== 2236 )
5408 basepoints0
= procSpell
->manaCost
* 40/100;
5409 if(basepoints0
<= 0)
5413 triggered_spell_id
= 34720;
5418 case SPELLFAMILY_PALADIN
:
5420 // Seal of Righteousness - melee proc dummy
5421 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5423 if(GetTypeId() != TYPEID_PLAYER
)
5427 switch (triggeredByAura
->GetId())
5429 case 21084: spellId
= 25742; break; // Rank 1
5430 case 20287: spellId
= 25740; break; // Rank 2
5431 case 20288: spellId
= 25739; break; // Rank 3
5432 case 20289: spellId
= 25738; break; // Rank 4
5433 case 20290: spellId
= 25737; break; // Rank 5
5434 case 20291: spellId
= 25736; break; // Rank 6
5435 case 20292: spellId
= 25735; break; // Rank 7
5436 case 20293: spellId
= 25713; break; // Rank 8
5437 case 27155: spellId
= 27156; break; // Rank 9
5439 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5442 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5443 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5445 float damageBasePoints
;
5446 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5448 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5450 // one hand weapon/no weapon
5451 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5453 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5455 // apply damage bonuses manually
5456 if(damagePoint
>= 0)
5457 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5459 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5460 return true; // no hidden cooldown
5462 // Seal of Blood do damage trigger
5463 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5465 switch(triggeredByAura
->GetEffIndex())
5468 // prevent chain triggering
5469 if(procSpell
&& procSpell
->Id
==31893 )
5472 triggered_spell_id
= 31893;
5477 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5479 triggered_spell_id
= 32221;
5485 switch(dummySpell
->Id
)
5487 // Holy Power (Redemption Armor set)
5493 // Set class defined buff
5494 switch (pVictim
->getClass())
5500 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5504 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5508 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5511 triggered_spell_id
= 28790; // Increases the friendly target's armor
5521 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5524 triggered_spell_id
= 31803;
5531 // if healed by another unit (pVictim)
5536 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5538 triggered_spell_id
= 31786;
5541 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5549 // Flash of light/Holy light
5550 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5552 triggered_spell_id
= 40471;
5556 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5558 triggered_spell_id
= 40472;
5564 if (!roll_chance_f(chance
))
5572 case SPELLFAMILY_SHAMAN
:
5574 switch(dummySpell
->Id
)
5576 // Totemic Power (The Earthshatterer set)
5582 // Set class defined buff
5583 switch (pVictim
->getClass())
5589 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5593 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5597 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5600 triggered_spell_id
= 28827; // Increases the friendly target's armor
5607 // Lesser Healing Wave (Totem of Flowing Water Relic)
5611 triggered_spell_id
= 28850;
5614 // Windfury Weapon (Passive) 1-5 Ranks
5617 if(GetTypeId()!=TYPEID_PLAYER
)
5620 if(!castItem
|| !castItem
->IsEquipped())
5623 // custom cooldown processing case
5624 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5628 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5630 case 283: spellId
= 33757; break; //1 Rank
5631 case 284: spellId
= 33756; break; //2 Rank
5632 case 525: spellId
= 33755; break; //3 Rank
5633 case 1669:spellId
= 33754; break; //4 Rank
5634 case 2636:spellId
= 33727; break; //5 Rank
5637 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5638 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5643 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5644 if(!windfurySpellEntry
)
5646 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5650 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5653 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5655 // Value gained from additional AP
5656 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5657 triggered_spell_id
= 33750;
5662 // Value gained from additional AP
5663 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5664 triggered_spell_id
= 25504;
5667 // apply cooldown before cast to prevent processing itself
5669 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5672 for ( uint32 i
= 0; i
<2; ++i
)
5673 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5677 // Shaman Tier 6 Trinket
5684 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5686 triggered_spell_id
= 40465; // Lightning Bolt
5689 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5691 triggered_spell_id
= 40465; // Lesser Healing Wave
5694 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5696 triggered_spell_id
= 40466; // Stormstrike
5702 if (!roll_chance_f(chance
))
5711 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5713 if(GetTypeId() != TYPEID_PLAYER
)
5717 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5719 triggered_spell_id
= 379;
5722 // Lightning Overload
5723 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5725 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5728 // custom cooldown processing case
5729 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5733 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5734 switch (procSpell
->Id
)
5737 case 403: spellId
= 45284; break; // Rank 1
5738 case 529: spellId
= 45286; break; // Rank 2
5739 case 548: spellId
= 45287; break; // Rank 3
5740 case 915: spellId
= 45288; break; // Rank 4
5741 case 943: spellId
= 45289; break; // Rank 5
5742 case 6041: spellId
= 45290; break; // Rank 6
5743 case 10391: spellId
= 45291; break; // Rank 7
5744 case 10392: spellId
= 45292; break; // Rank 8
5745 case 15207: spellId
= 45293; break; // Rank 9
5746 case 15208: spellId
= 45294; break; // Rank 10
5747 case 25448: spellId
= 45295; break; // Rank 11
5748 case 25449: spellId
= 45296; break; // Rank 12
5750 case 421: spellId
= 45297; break; // Rank 1
5751 case 930: spellId
= 45298; break; // Rank 2
5752 case 2860: spellId
= 45299; break; // Rank 3
5753 case 10605: spellId
= 45300; break; // Rank 4
5754 case 25439: spellId
= 45301; break; // Rank 5
5755 case 25442: spellId
= 45302; break; // Rank 6
5757 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5760 // No thread generated mod
5761 SpellModifier
*mod
= new SpellModifier
;
5762 mod
->op
= SPELLMOD_THREAT
;
5764 mod
->type
= SPELLMOD_PCT
;
5765 mod
->spellId
= dummySpell
->Id
;
5767 mod
->lastAffected
= NULL
;
5768 mod
->mask
= 0x0000000000000003LL
;
5770 ((Player
*)this)->AddSpellMod(mod
, true);
5772 // Remove cooldown (Chain Lightning - have Category Recovery time)
5773 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5774 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5776 // Hmmm.. in most case spells already set half basepoints but...
5777 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5779 // 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.
5780 // So - no add changes :)
5781 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5783 ((Player
*)this)->AddSpellMod(mod
, false);
5785 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5786 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5796 // processed charge only counting case
5797 if(!triggered_spell_id
)
5800 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5804 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5809 if(!target
|| target
!=this && !target
->isAlive())
5812 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5816 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5818 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5820 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5821 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5826 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5828 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5830 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5831 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5833 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5834 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5835 int32 basepoints0
= 0;
5837 switch(auraSpellInfo
->SpellFamilyName
)
5839 case SPELLFAMILY_GENERIC
:
5841 switch(auraSpellInfo
->Id
)
5843 // Aegis of Preservation
5845 //Aegis Heal (instead non-existed triggered spell)
5846 triggered_spell_id
= 23781;
5849 // Elune's Touch (moonkin mana restore)
5852 // Elune's Touch (instead non-existed triggered spell)
5853 triggered_spell_id
= 33926;
5854 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5861 // only for cast with mana price
5862 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5864 break; // fall through to normal cast
5869 // at melee hit call std triggered spell
5870 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5871 break; // fall through to normal cast
5873 // Mark of Conquest - else (at range hit) called custom case
5874 triggered_spell_id
= 39557;
5880 return true; // nothing to do
5881 // Forgotten Knowledge (Blade of Wizardry)
5883 // only for harmful enemy targeted spell
5884 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5886 break; // fall through to normal cast
5887 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5890 // proc only at non-crit hits
5891 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5893 break; // fall through to normal cast
5895 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5901 //only periodic damage can trigger spell
5903 for(int j
= 0; j
< 3; ++j
)
5905 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5906 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5907 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5916 break; // fall through to normal cast
5918 // Evasive Maneuvers (Commendation of Kael'thas)
5921 // damage taken that reduces below 35% health
5922 // does NOT mean you must have been >= 35% before
5923 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5925 break; // fall through to normal cast
5929 switch(triggered_spell_id
)
5934 // applied only for main target
5935 if(!pVictim
|| pVictim
!= getVictim())
5938 // continue normal case
5941 // Shamanistic Rage triggered spell
5943 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5948 case SPELLFAMILY_MAGE
:
5950 switch(auraSpellInfo
->SpellIconID
)
5954 //Blazing Speed (instead non-existed triggered spell)
5955 triggered_spell_id
= 31643;
5959 switch(auraSpellInfo
->Id
)
5961 // Persistent Shield (Scarab Brooch)
5963 basepoints0
= int32(damage
* 0.15f
);
5968 case SPELLFAMILY_WARRIOR
:
5971 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5973 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5974 //and effect[1]==TriggerSpell
5975 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5977 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5980 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5981 break; // fall through to normal cast
5985 case SPELLFAMILY_WARLOCK
:
5988 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5990 // last case for Hellfire that damage caster also but don't must stun caster
5991 if( pVictim
== this )
5996 switch (triggeredByAura
->GetId())
5998 case 18096: chance
= 13.0f
; break;
5999 case 18073: chance
= 26.0f
; break;
6001 if (!roll_chance_f(chance
))
6004 // Pyroclasm (instead non-existed triggered spell)
6005 triggered_spell_id
= 18093;
6010 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
6013 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
6014 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
6016 //Improved Drain Soul
6017 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
6019 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
6020 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
6023 triggered_spell_id
= 18371;
6031 break; // fall through to normal cast
6035 case SPELLFAMILY_PRIEST
:
6038 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6040 switch (triggeredByAura
->GetSpellProto()->Id
)
6042 case 27811: triggered_spell_id
= 27813; break;
6043 case 27815: triggered_spell_id
= 27817; break;
6044 case 27816: triggered_spell_id
= 27818; break;
6046 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6050 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6051 basepoints0
= heal_amount
/3;
6056 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
[0]==7958)
6058 switch(triggeredByAura
->GetSpellProto()->Id
)
6061 triggered_spell_id
= 28377; break; // Rank 1
6063 triggered_spell_id
= 28378; break; // Rank 2
6065 triggered_spell_id
= 28379; break; // Rank 3
6067 triggered_spell_id
= 28380; break; // Rank 4
6069 triggered_spell_id
= 28381; break; // Rank 5
6071 triggered_spell_id
= 28382; break; // Rank 6
6073 triggered_spell_id
= 28385; break; // Rank 7
6075 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6083 case SPELLFAMILY_DRUID
:
6085 switch(auraSpellInfo
->Id
)
6087 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6090 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6092 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6093 triggered_spell_id
= 34299;
6096 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6103 triggered_spell_id
=37340; break;// Ursine Blessing
6105 triggered_spell_id
=37341; break;// Feline Blessing
6107 triggered_spell_id
=37342; break;// Slyvan Blessing
6109 triggered_spell_id
=37343; break;// Lunar Blessing
6111 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6122 case SPELLFAMILY_ROGUE
:
6124 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6126 switch(auraSpellInfo
->SpellIconID
)
6131 // skip non offhand attacks
6132 if(attackType
!=OFF_ATTACK
)
6134 break; // fall through to normal cast
6140 case SPELLFAMILY_PALADIN
:
6142 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6144 switch(auraSpellInfo
->Id
)
6146 // Lightning Capacitor
6149 // trinket ProcTriggerSpell but for safe checks for player
6150 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6153 if(((Player
*)this)->HasSpellCooldown(37657))
6157 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6158 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6159 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6163 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6164 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6165 if((*itr
)->GetId()==37658)
6168 // release at 3 aura in stack
6170 return true; // main triggered spell casted anyway
6172 RemoveAurasDueToSpell(37658);
6173 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6178 // Healing Trance (instead non-existed triggered spell)
6179 triggered_spell_id
= 37706;
6182 // HoTs on Heals (Fel Reaver's Piston trinket)
6185 // at direct heal effect
6186 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6189 // single proc at time
6190 AuraList
const& scAuras
= GetSingleCastAuras();
6191 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6192 if((*itr
)->GetId()==triggered_spell_id
)
6195 // positive cast at victim instead self
6200 switch(auraSpellInfo
->SpellIconID
)
6204 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6212 // procspell is triggered spell but we need mana cost of original casted spell
6213 uint32 originalSpellId
= procSpell
->Id
;
6216 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6218 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6220 switch(procSpell
->Id
)
6222 case 25914: originalSpellId
= 20473; break;
6223 case 25913: originalSpellId
= 20929; break;
6224 case 25903: originalSpellId
= 20930; break;
6225 case 27175: originalSpellId
= 27174; break;
6226 case 33074: originalSpellId
= 33072; break;
6228 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6234 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6237 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6241 // percent stored in effect 1 (class scripts) base points
6242 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6244 basepoints0
= originalSpell
->manaCost
*percent
/100;
6245 triggered_spell_id
= 20272;
6254 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6256 switch(auraSpellInfo
->SpellIconID
)
6258 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6261 if(!pVictim
|| !pVictim
->isAlive())
6264 switch(triggeredByAura
->GetSpellProto()->Id
)
6267 triggered_spell_id
= 20268; // Rank 1
6270 triggered_spell_id
= 20352; // Rank 2
6273 triggered_spell_id
= 20353; // Rank 3
6276 triggered_spell_id
= 27165; // Rank 4
6279 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6283 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6284 return true; // no hidden cooldown
6286 //Judgement of Light
6289 if(!pVictim
|| !pVictim
->isAlive())
6292 // overwrite non existing triggered spell call in spell.dbc
6293 switch(triggeredByAura
->GetSpellProto()->Id
)
6296 triggered_spell_id
= 20267; // Rank 1
6299 triggered_spell_id
= 20341; // Rank 2
6302 triggered_spell_id
= 20342; // Rank 3
6305 triggered_spell_id
= 20343; // Rank 4
6308 triggered_spell_id
= 27163; // Rank 5
6311 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6314 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6315 return true; // no hidden cooldown
6319 // custom check for proc spell
6320 switch(auraSpellInfo
->Id
)
6322 // Bonus Healing (item spell)
6325 if(!pVictim
|| !pVictim
->isAlive())
6328 // bonus if health < 50%
6329 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6332 // cast at target positive spell
6337 switch(triggered_spell_id
)
6341 // prevent chain of triggered spell from same triggered spell
6342 if(procSpell
&& procSpell
->Id
==20424)
6348 case SPELLFAMILY_SHAMAN
:
6350 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6352 switch(auraSpellInfo
->SpellIconID
)
6356 switch(auraSpellInfo
->Id
)
6358 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6360 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6361 triggered_spell_id
= 23552;
6365 case 23552: // Lightning Shield - trigger shield damage
6367 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6368 triggered_spell_id
= 27635;
6375 // Mana Surge (Shaman T1 bonus)
6381 basepoints0
= procSpell
->manaCost
* 35/100;
6382 triggered_spell_id
= 23571;
6389 if(GetTypeId()!=TYPEID_PLAYER
)
6392 // damage taken that reduces below 30% health
6393 // does NOT mean you must have been >= 30% before
6394 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6397 triggered_spell_id
= 31616;
6399 // need check cooldown now
6400 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6403 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6405 if(pVictim
&& pVictim
->isAlive())
6406 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6412 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6413 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
[0]==7358)
6420 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
[0]==37)
6422 // overwrite non existing triggered spell call in spell.dbc
6423 switch(triggeredByAura
->GetSpellProto()->Id
)
6426 triggered_spell_id
= 26364; break; // Rank 1
6428 triggered_spell_id
= 26365; break; // Rank 2
6430 triggered_spell_id
= 26366; break; // Rank 3
6432 triggered_spell_id
= 26367; break; // Rank 4
6434 triggered_spell_id
= 26369; break; // Rank 5
6436 triggered_spell_id
= 26370; break; // Rank 6
6438 triggered_spell_id
= 26363; break; // Rank 7
6440 triggered_spell_id
= 26371; break; // Rank 8
6442 triggered_spell_id
= 26372; break; // Rank 9
6444 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6455 // standard non-dummy case
6456 if(!triggered_spell_id
)
6458 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6462 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6466 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6470 // not allow proc extra attack spell at extra attack
6471 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6474 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6478 if(!target
|| target
!=this && !target
->isAlive())
6482 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6484 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6486 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6487 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6492 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6494 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6496 if(!pVictim
|| !pVictim
->isAlive())
6499 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6500 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6502 uint32 triggered_spell_id
= 0;
6506 case 836: // Improved Blizzard (Rank 1)
6508 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6510 triggered_spell_id
= 12484;
6513 case 988: // Improved Blizzard (Rank 2)
6515 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6517 triggered_spell_id
= 12485;
6520 case 989: // Improved Blizzard (Rank 3)
6522 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6524 triggered_spell_id
= 12486;
6527 case 4086: // Improved Mend Pet (Rank 1)
6528 case 4087: // Improved Mend Pet (Rank 2)
6530 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6531 if(!roll_chance_i(chance
))
6534 triggered_spell_id
= 24406;
6537 case 4533: // Dreamwalker Raiment 2 pieces bonus
6540 if (!roll_chance_i(50))
6543 switch (pVictim
->getPowerType())
6545 case POWER_MANA
: triggered_spell_id
= 28722; break;
6546 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6547 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6553 case 4537: // Dreamwalker Raiment 6 pieces bonus
6554 triggered_spell_id
= 28750; // Blessing of the Claw
6556 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6557 triggered_spell_id
= 37445; // Mana Surge
6562 if(!triggered_spell_id
)
6565 // standard non-dummy case
6566 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6570 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6574 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6577 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6579 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6580 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6585 void Unit::setPowerType(Powers new_powertype
)
6587 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6589 if(GetTypeId() == TYPEID_PLAYER
)
6591 if(((Player
*)this)->GetGroup())
6592 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6594 else if(((Creature
*)this)->isPet())
6596 Pet
*pet
= ((Pet
*)this);
6597 if(pet
->isControlled())
6599 Unit
*owner
= GetOwner();
6600 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6601 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6605 switch(new_powertype
)
6611 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6612 SetPower( POWER_RAGE
,0);
6615 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6616 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6619 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6620 SetPower( POWER_ENERGY
,0);
6622 case POWER_HAPPINESS
:
6623 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6624 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6629 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6631 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6634 static uint64 guid
= 0; // prevent repeating spam same faction problem
6636 if(GetGUID() != guid
)
6638 if(GetTypeId() == TYPEID_PLAYER
)
6639 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6641 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6648 bool Unit::IsHostileTo(Unit
const* unit
) const
6650 // always non-hostile to self
6654 // always non-hostile to GM in GM mode
6655 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6658 // always hostile to enemy
6659 if(getVictim()==unit
|| unit
->getVictim()==this)
6662 // test pet/charm masters instead pers/charmeds
6663 Unit
const* testerOwner
= GetCharmerOrOwner();
6664 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6666 // always hostile to owner's enemy
6667 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6670 // always hostile to enemy owner
6671 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6674 // always hostile to owner of owner's enemy
6675 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6678 Unit
const* tester
= testerOwner
? testerOwner
: this;
6679 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6681 // always non-hostile to target with common owner, or to owner/pet
6685 // special cases (Duel, etc)
6686 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6688 Player
const* pTester
= (Player
const*)tester
;
6689 Player
const* pTarget
= (Player
const*)target
;
6692 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6696 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6700 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6704 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6708 // Green/Blue (can't attack)
6709 if(pTester
->GetTeam()==pTarget
->GetTeam())
6712 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6713 return pTester
->IsPvP() && pTarget
->IsPvP();
6716 // faction base cases
6717 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6718 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6719 if(!tester_faction
|| !target_faction
)
6722 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6725 // PvC forced reaction and reputation case
6726 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6729 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6730 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6731 return forceItr
->second
<= REP_HOSTILE
;
6733 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6734 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6735 if(raw_target_faction
->reputationListID
>=0)
6736 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6737 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6739 // CvP forced reaction and reputation case
6740 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6743 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6744 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6745 return forceItr
->second
<= REP_HOSTILE
;
6747 // apply reputation state
6748 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6749 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6750 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6753 // common faction based case (CvC,PvC,CvP)
6754 return tester_faction
->IsHostileTo(*target_faction
);
6757 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6759 // always friendly to self
6763 // always friendly to GM in GM mode
6764 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6767 // always non-friendly to enemy
6768 if(getVictim()==unit
|| unit
->getVictim()==this)
6771 // test pet/charm masters instead pers/charmeds
6772 Unit
const* testerOwner
= GetCharmerOrOwner();
6773 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6775 // always non-friendly to owner's enemy
6776 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6779 // always non-friendly to enemy owner
6780 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6783 // always non-friendly to owner of owner's enemy
6784 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6787 Unit
const* tester
= testerOwner
? testerOwner
: this;
6788 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6790 // always friendly to target with common owner, or to owner/pet
6794 // special cases (Duel)
6795 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6797 Player
const* pTester
= (Player
const*)tester
;
6798 Player
const* pTarget
= (Player
const*)target
;
6801 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6805 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6809 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6813 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6817 // Green/Blue (non-attackable)
6818 if(pTester
->GetTeam()==pTarget
->GetTeam())
6821 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6822 return !pTarget
->IsPvP();
6825 // faction base cases
6826 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6827 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6828 if(!tester_faction
|| !target_faction
)
6831 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6834 // PvC forced reaction and reputation case
6835 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6838 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6839 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6840 return forceItr
->second
>= REP_FRIENDLY
;
6842 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6843 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6844 if(raw_target_faction
->reputationListID
>=0)
6845 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6846 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6848 // CvP forced reaction and reputation case
6849 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6852 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6853 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6854 return forceItr
->second
>= REP_FRIENDLY
;
6856 // apply reputation state
6857 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6858 if(raw_tester_faction
->reputationListID
>=0 )
6859 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6862 // common faction based case (CvC,PvC,CvP)
6863 return tester_faction
->IsFriendlyTo(*target_faction
);
6866 bool Unit::IsHostileToPlayers() const
6868 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6872 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6873 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6876 return my_faction
->IsHostileToPlayers();
6879 bool Unit::IsNeutralToAll() const
6881 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6885 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6886 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6889 return my_faction
->IsNeutralToAll();
6892 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6894 if(!victim
|| victim
== this)
6897 // dead units can neither attack nor be attacked
6898 if(!isAlive() || !victim
->isAlive())
6901 // player cannot attack in mount state
6902 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6905 // nobody can attack GM in GM-mode
6906 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6908 if(((Player
*)victim
)->isGameMaster())
6913 if(((Creature
*)victim
)->IsInEvadeMode())
6917 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6918 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6919 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6923 if (m_attacking
== victim
)
6925 // switch to melee attack from ranged/magic
6926 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6928 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6929 SendAttackStart(victim
);
6938 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6941 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6942 m_attacking
= victim
;
6943 m_attacking
->_addAttacker(this);
6945 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6946 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6948 if(GetTypeId()==TYPEID_UNIT
)
6950 WorldPacket
data(SMSG_AI_REACTION
, 12);
6951 data
<< uint64(GetGUID());
6952 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6953 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6955 ((Creature
*)this)->CallAssistance();
6956 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6959 // delay offhand weapon attack to next attack time
6960 if(haveOffhandWeapon())
6961 resetAttackTimer(OFF_ATTACK
);
6964 SendAttackStart(victim
);
6969 bool Unit::AttackStop()
6974 Unit
* victim
= m_attacking
;
6976 m_attacking
->_removeAttacker(this);
6980 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6982 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6984 InterruptSpell(CURRENT_MELEE_SPELL
);
6986 if( GetTypeId()==TYPEID_UNIT
)
6988 // reset call assistance
6989 ((Creature
*)this)->SetNoCallAssistance(false);
6992 SendAttackStop(victim
);
6997 void Unit::CombatStop(bool cast
)
6999 if(cast
& IsNonMeleeSpellCasted(false))
7000 InterruptNonMeleeSpells(false);
7003 RemoveAllAttackers();
7004 if( GetTypeId()==TYPEID_PLAYER
)
7005 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
7009 void Unit::CombatStopWithPets(bool cast
)
7012 if(Pet
* pet
= GetPet())
7013 pet
->CombatStop(cast
);
7014 if(Unit
* charm
= GetCharm())
7015 charm
->CombatStop(cast
);
7016 if(GetTypeId()==TYPEID_PLAYER
)
7018 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
7019 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
7020 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
7021 guardian
->CombatStop(cast
);
7025 bool Unit::isAttackingPlayer() const
7027 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
7030 Pet
* pet
= GetPet();
7031 if(pet
&& pet
->isAttackingPlayer())
7034 Unit
* charmed
= GetCharm();
7035 if(charmed
&& charmed
->isAttackingPlayer())
7038 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7042 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7043 if(totem
&& totem
->isAttackingPlayer())
7051 void Unit::RemoveAllAttackers()
7053 while (!m_attackers
.empty())
7055 AttackerSet::iterator iter
= m_attackers
.begin();
7056 if(!(*iter
)->AttackStop())
7058 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
7059 m_attackers
.erase(iter
);
7064 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7068 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7070 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7071 if(GetTypeId() == TYPEID_PLAYER
)
7073 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7074 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7076 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7077 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7078 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7079 if (spellInfo
->CasterAuraState
== flag
)
7080 CastSpell(this, itr
->first
, true, NULL
);
7087 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7089 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7090 Unit::AuraMap
& tAuras
= GetAuras();
7091 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7093 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7094 if (spellProto
->CasterAuraState
== flag
)
7096 // exceptions (applied at state but not removed at state change)
7098 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7113 Unit
*Unit::GetOwner() const
7115 uint64 ownerid
= GetOwnerGUID();
7118 return ObjectAccessor::GetUnit(*this, ownerid
);
7121 Unit
*Unit::GetCharmer() const
7123 if(uint64 charmerid
= GetCharmerGUID())
7124 return ObjectAccessor::GetUnit(*this, charmerid
);
7128 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7130 uint64 guid
= GetCharmerOrOwnerGUID();
7131 if(IS_PLAYER_GUID(guid
))
7132 return ObjectAccessor::GetPlayer(*this, guid
);
7134 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7137 Pet
* Unit::GetPet() const
7139 if(uint64 pet_guid
= GetPetGUID())
7141 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7144 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7145 const_cast<Unit
*>(this)->SetPet(0);
7151 Unit
* Unit::GetCharm() const
7153 if(uint64 charm_guid
= GetCharmGUID())
7155 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7158 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7159 const_cast<Unit
*>(this)->SetCharm(0);
7165 void Unit::SetPet(Pet
* pet
)
7167 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7169 // FIXME: hack, speed must be set only at follow
7171 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7172 pet
->SetSpeed(UnitMoveType(i
), m_speed_rate
[i
], true);
7175 void Unit::SetCharm(Unit
* pet
)
7177 SetUInt64Value(UNIT_FIELD_CHARM
, pet
? pet
->GetGUID() : 0);
7179 if(GetTypeId() == TYPEID_PLAYER
)
7180 ((Player
*)this)->m_mover
= pet
? pet
: this;
7183 void Unit::UnsummonAllTotems()
7185 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7190 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7191 if (OldTotem
&& OldTotem
->isTotem())
7192 ((Totem
*)OldTotem
)->UnSummon();
7196 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7199 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7200 data
.append(pVictim
->GetPackGUID());
7201 data
.append(GetPackGUID());
7202 data
<< uint32(SpellID
);
7203 data
<< uint32(Damage
);
7204 data
<< uint32(0); // over healing?
7205 data
<< uint8(critical
? 1 : 0);
7206 data
<< uint8(0); // unused in client?
7207 SendMessageToSet(&data
, true);
7210 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7212 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7213 data
.append(pVictim
->GetPackGUID());
7214 data
.append(GetPackGUID());
7215 data
<< uint32(SpellID
);
7216 data
<< uint32(powertype
);
7217 data
<< uint32(Damage
);
7218 SendMessageToSet(&data
, true);
7221 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7223 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7226 int32 BonusDamage
= 0;
7227 if( GetTypeId()==TYPEID_UNIT
)
7229 // Pets just add their bonus damage to their spell damage
7230 // note that their spell damage is just gain of their own auras
7231 if (((Creature
*)this)->isPet())
7233 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7235 // For totems get damage bonus from owner (statue isn't totem in fact)
7236 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7238 if(Unit
* owner
= GetOwner())
7239 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7244 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7246 // Taken/Done fixed damage bonus auras
7247 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7248 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7250 // Damage over Time spells bonus calculation
7251 float DotFactor
= 1.0f
;
7252 if(damagetype
== DOT
)
7254 int32 DotDuration
= GetSpellDuration(spellProto
);
7258 if(DotDuration
> 30000) DotDuration
= 30000;
7259 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7261 for(int j
= 0; j
< 3; j
++)
7263 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7264 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7265 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7272 if(spellProto
->EffectAmplitude
[x
] != 0)
7273 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7276 DoneAdvertisedBenefit
/= DotTicks
;
7277 TakenAdvertisedBenefit
/= DotTicks
;
7282 // Taken/Done total percent damage auras
7283 float DoneTotalMod
= 1.0f
;
7284 float TakenTotalMod
= 1.0f
;
7287 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7288 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7290 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7291 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7292 // -1 == any item class (not wand then)
7293 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7294 // 0 == any inventory type (not wand then)
7296 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7300 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7301 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7302 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7303 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7304 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7307 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7308 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7309 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7310 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7312 // .. taken pct: scripted (increases damage of * against targets *)
7313 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7314 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7316 switch((*i
)->GetModifier()->m_miscvalue
)
7319 case 4920: case 4919:
7320 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7321 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7325 // .. taken pct: dummy auras
7326 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7327 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7329 switch((*i
)->GetSpellProto()->SpellIconID
)
7333 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7335 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7337 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7338 if (mod
< (*i
)->GetModifier()->m_amount
)
7339 mod
= (*i
)->GetModifier()->m_amount
;
7340 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7345 for(int j
=0;j
<3;j
++)
7347 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7349 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7357 // Distribute Damage over multiple effects, reduce by AoE
7358 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7360 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7361 for(int j
= 0; j
< 3; ++j
)
7363 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7364 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7371 switch(spellProto
->SpellFamilyName
)
7373 case SPELLFAMILY_MAGE
:
7374 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7375 if(spellProto
->Id
==12654)
7380 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7382 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7383 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7384 TakenTotalMod
*= 3.0f
;
7386 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7387 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7389 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7390 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7392 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7393 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7396 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7399 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7403 // Arcane Missiles triggered spell
7404 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7408 // Blizzard triggered spell
7409 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7414 case SPELLFAMILY_WARLOCK
:
7416 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7418 CastingTime
= 2800; // 80% from +shadow damage
7419 DoneTotalMod
= 1.0f
;
7420 TakenTotalMod
= 1.0f
;
7423 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7425 CastingTime
= 3360; // 96% from +shadow damage
7426 DoneTotalMod
= 1.0f
;
7427 TakenTotalMod
= 1.0f
;
7429 // Soul Fire - 115% of Fire Damage
7430 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7434 // Curse of Agony - 120% of Shadow Damage
7435 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7439 // Drain Mana - 0% of Shadow Damage
7440 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7444 // Drain Soul 214.3%
7445 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7450 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7452 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7454 // Unstable Affliction - 180%
7455 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7460 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7465 case SPELLFAMILY_PALADIN
:
7466 // Consecration - 95% of Holy Damage
7467 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7472 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7473 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7475 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7476 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7478 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7479 CastingTime
= uint32(wspeed
*3500*0.102f
);
7481 CastingTime
= uint32(wspeed
*3500*0.098f
);
7483 // Judgement of Righteousness - 73%
7484 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7488 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7489 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7494 // Holy shield - 5% of Holy Damage
7495 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7499 // Blessing of Sanctuary - 0%
7500 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7504 // Seal of Righteousness trigger - already computed for parent spell
7505 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7510 case SPELLFAMILY_SHAMAN
:
7512 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7514 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7515 CastingTime
= 749; // ignore CastingTime and use as modifier
7516 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7517 CastingTime
= 280; // ignore CastingTime and use as modifier
7518 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7519 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7521 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7522 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7523 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7525 case SPELLFAMILY_PRIEST
:
7526 // Mana Burn - 0% of Shadow Damage
7527 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7531 // Mind Flay - 59% of Shadow Damage
7532 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7536 // Holy Fire - 86.71%, DoT - 16.5%
7537 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7539 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7540 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7542 // Shadowguard - 28% per charge
7543 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7547 // Touch of Weakeness - 10%
7548 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7552 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7553 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7558 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7563 case SPELLFAMILY_DRUID
:
7564 // Hurricane triggered spell
7565 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7570 case SPELLFAMILY_WARRIOR
:
7571 case SPELLFAMILY_HUNTER
:
7572 case SPELLFAMILY_ROGUE
:
7579 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7581 // Spellmod SpellDamage
7582 float SpellModSpellDamage
= 100.0f
;
7584 if(Player
* modOwner
= GetSpellModOwner())
7585 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7587 SpellModSpellDamage
/= 100.0f
;
7589 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7590 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7592 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7594 // Add flat bonus from spell damage versus
7595 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7597 // apply spellmod to Done damage
7598 if(Player
* modOwner
= GetSpellModOwner())
7599 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7601 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7603 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7604 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7606 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7609 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7611 int32 DoneAdvertisedBenefit
= 0;
7614 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7615 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7616 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7617 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7618 // -1 == any item class (not wand then)
7619 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7620 // 0 == any inventory type (not wand then)
7621 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7623 if (GetTypeId() == TYPEID_PLAYER
)
7625 // Damage bonus from stats
7626 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7627 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7629 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7631 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7632 uint8 eff
= (*i
)->GetEffIndex();
7634 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7635 Stats usedStat
= STAT_INTELLECT
;
7636 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7637 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7639 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7642 // ... and attack power
7643 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7644 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7645 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7646 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7649 return DoneAdvertisedBenefit
;
7652 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7654 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7656 int32 TakenAdvertisedBenefit
= 0;
7657 // ..done (for creature type by mask) in taken
7658 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7659 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7660 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7661 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7664 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7665 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7666 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7667 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7669 return TakenAdvertisedBenefit
;
7672 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7674 // not critting spell
7675 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7678 float crit_chance
= 0.0f
;
7679 switch(spellProto
->DmgClass
)
7681 case SPELL_DAMAGE_CLASS_NONE
:
7683 case SPELL_DAMAGE_CLASS_MAGIC
:
7685 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7687 // For other schools
7688 else if (GetTypeId() == TYPEID_PLAYER
)
7689 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7692 crit_chance
= m_baseSpellCritChance
;
7693 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7696 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7698 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7699 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7700 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7701 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7702 // Modify by player victim resilience
7703 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7704 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7705 // scripted (increase crit chance ... against ... target by x%
7706 if(pVictim
->isFrozen()) // Shatter
7708 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7709 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7711 switch((*i
)->GetModifier()->m_miscvalue
)
7713 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7714 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7715 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7716 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7717 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7724 case SPELL_DAMAGE_CLASS_MELEE
:
7725 case SPELL_DAMAGE_CLASS_RANGED
:
7729 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7730 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7731 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7739 // only players use intelligence for critical chance computations
7740 if(Player
* modOwner
= GetSpellModOwner())
7741 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7743 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7744 if (roll_chance_f(crit_chance
))
7749 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7751 // Calculate critical bonus
7753 switch(spellProto
->DmgClass
)
7755 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7756 case SPELL_DAMAGE_CLASS_RANGED
:
7757 // TODO: write here full calculation for melee/ranged spells
7758 crit_bonus
= damage
;
7761 crit_bonus
= damage
/ 2; // for spells is 50%
7765 // adds additional damage to crit_bonus (from talents)
7766 if(Player
* modOwner
= GetSpellModOwner())
7767 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7771 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7772 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7776 damage
+= crit_bonus
;
7781 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7783 // For totems get healing bonus from owner (statue isn't totem in fact)
7784 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7785 if(Unit
* owner
= GetOwner())
7786 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7790 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7791 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7792 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7793 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7796 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7797 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7800 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7802 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7803 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7805 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7806 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7808 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7811 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7812 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7814 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7815 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7820 float ActualBenefit
= 0.0f
;
7822 if (AdvertisedBenefit
!= 0)
7824 // Healing over Time spells
7825 float DotFactor
= 1.0f
;
7826 if(damagetype
== DOT
)
7828 int32 DotDuration
= GetSpellDuration(spellProto
);
7832 if(DotDuration
> 30000) DotDuration
= 30000;
7833 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7835 for(int j
= 0; j
< 3; j
++)
7837 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7838 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7839 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7846 if(spellProto
->EffectAmplitude
[x
] != 0)
7847 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7849 AdvertisedBenefit
/= DotTicks
;
7853 // distribute healing to all effects, reduce AoE damage
7854 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7856 // 0% bonus for damage and healing spells for leech spells from healing bonus
7857 for(int j
= 0; j
< 3; ++j
)
7859 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7860 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7868 switch (spellProto
->SpellFamilyName
)
7870 case SPELLFAMILY_SHAMAN
:
7871 // Healing stream from totem (add 6% per tick from hill bonus owner)
7872 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7874 // Earth Shield 30% per charge
7875 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7878 case SPELLFAMILY_DRUID
:
7880 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7882 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7883 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7885 // Tranquility triggered spell
7886 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7889 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7892 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7894 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7895 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7898 case SPELLFAMILY_PRIEST
:
7900 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7903 case SPELLFAMILY_PALADIN
:
7904 // Seal and Judgement of Light
7905 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7908 case SPELLFAMILY_WARRIOR
:
7909 case SPELLFAMILY_ROGUE
:
7910 case SPELLFAMILY_HUNTER
:
7915 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7917 // Spellmod SpellDamage
7918 float SpellModSpellDamage
= 100.0f
;
7920 if(Player
* modOwner
= GetSpellModOwner())
7921 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7923 SpellModSpellDamage
/= 100.0f
;
7925 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7928 // use float as more appropriate for negative values and percent applying
7929 float heal
= healamount
+ ActualBenefit
;
7931 // TODO: check for ALL/SPELLS type
7932 // Healing done percent
7933 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7934 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7935 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7937 // apply spellmod to Done amount
7938 if(Player
* modOwner
= GetSpellModOwner())
7939 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7941 // Healing Wave cast
7942 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7944 // Search for Healing Way on Victim (stack up to 3 time)
7946 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7947 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7948 if((*itr
)->GetId() == 29203)
7949 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7952 heal
= heal
* (100 + pctMod
) / 100;
7955 // Healing taken percent
7956 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7958 heal
*= (100.0f
+ minval
) / 100.0f
;
7960 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7962 heal
*= (100.0f
+ maxval
) / 100.0f
;
7964 if (heal
< 0) heal
= 0;
7966 return uint32(heal
);
7969 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7971 int32 AdvertisedBenefit
= 0;
7973 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7974 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7975 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7976 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7978 // Healing bonus of spirit, intellect and strength
7979 if (GetTypeId() == TYPEID_PLAYER
)
7981 // Healing bonus from stats
7982 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7983 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7985 // stat used dependent from misc value (stat index)
7986 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7987 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7990 // ... and attack power
7991 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7992 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7993 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7994 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7996 return AdvertisedBenefit
;
7999 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
8001 int32 AdvertisedBenefit
= 0;
8002 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
8003 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8004 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
8005 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
8006 return AdvertisedBenefit
;
8009 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
8011 // no charges dependent checks
8012 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8013 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8014 if(itr
->type
& shoolMask
)
8017 // charges dependent checks
8018 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
8019 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
8021 if(itr
->type
& shoolMask
)
8025 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
8026 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
8028 if((*auraItr
)->GetId()==itr
->spellId
)
8030 if((*auraItr
)->m_procCharges
> 0)
8032 --(*auraItr
)->m_procCharges
;
8033 if((*auraItr
)->m_procCharges
==0)
8034 RemoveAurasDueToSpell(itr
->spellId
);
8047 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8054 //FIX ME this hack: don't get feared if stunned
8055 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8057 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8061 // not have spells with charges currently
8062 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8063 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8064 if(itr
->type
== spellInfo
->Dispel
)
8067 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8069 // not have spells with charges currently
8070 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8071 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8072 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8073 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8077 // charges dependent checks
8079 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8080 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8082 if(itr
->type
== spellInfo
->Mechanic
)
8086 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8087 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8089 if((*auraItr
)->GetId()==itr
->spellId
)
8091 if((*auraItr
)->m_procCharges
> 0)
8093 --(*auraItr
)->m_procCharges
;
8094 if((*auraItr
)->m_procCharges
==0)
8095 RemoveAurasDueToSpell(itr
->spellId
);
8108 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8110 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8111 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8112 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8113 if(itr
->type
== effect
)
8116 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8117 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8118 if(itr
->type
== mechanic
)
8124 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8129 uint32 family
= spellInfo
->SpellFamilyName
;
8130 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8132 if((family
== 5 && flags
== 256) || //Searing Pain
8133 (family
== 6 && flags
== 8192) || //Mind Blast
8134 (family
== 11 && flags
== 1048576)) //Earth Shock
8140 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8148 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8150 // Taken/Done fixed damage bonus auras
8151 int32 DoneFlatBenefit
= 0;
8152 int32 TakenFlatBenefit
= 0;
8154 // ..done (for creature type by mask) in taken
8155 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8156 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8157 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8158 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8161 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8163 // ..done (base at attack power for marked target and base at attack power for creature type)
8165 if(attType
== RANGED_ATTACK
)
8167 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8169 // ..done (base at attack power and creature type)
8170 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8171 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8172 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8173 APbonus
+= (*i
)->GetModifier()->m_amount
;
8177 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8179 // ..done (base at attack power and creature type)
8180 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8181 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8182 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8183 APbonus
+= (*i
)->GetModifier()->m_amount
;
8186 if (APbonus
!=0) // Can be negative
8188 bool normalized
= false;
8191 for (uint8 i
= 0; i
<3;i
++)
8193 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8201 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8205 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8206 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8207 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8208 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8210 if(attType
!=RANGED_ATTACK
)
8211 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8213 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8215 // Done/Taken total percent damage auras
8216 float DoneTotalMod
= 1;
8217 float TakenTotalMod
= 1;
8220 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8221 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8223 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8224 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8225 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8226 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8229 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8230 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8231 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8232 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8234 // .. taken pct: dummy auras
8235 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8236 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8238 switch((*i
)->GetSpellProto()->SpellIconID
)
8242 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8244 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8246 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8247 if (mod
< (*i
)->GetModifier()->m_amount
)
8248 mod
= (*i
)->GetModifier()->m_amount
;
8249 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8254 if(spellProto
==NULL
)
8256 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8257 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8258 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8263 // .. taken pct: class scripts
8264 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8265 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8267 switch((*i
)->GetMiscValue())
8269 case 6427: case 6428: // Dirty Deeds
8270 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8272 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8273 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8275 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8279 // effect 0 have expected value but in negative state
8280 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8286 if(attType
!= RANGED_ATTACK
)
8288 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8289 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8290 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8294 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8295 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8296 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8299 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8301 // apply spellmod to Done damage
8304 if(Player
* modOwner
= GetSpellModOwner())
8305 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8308 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8310 // bonus result can be negative
8311 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8314 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8318 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8321 if(itr
->type
== type
)
8323 m_spellImmune
[op
].erase(itr
);
8324 next
= m_spellImmune
[op
].begin();
8328 Immune
.spellId
= spellId
;
8330 m_spellImmune
[op
].push_back(Immune
);
8334 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8336 if(itr
->spellId
== spellId
)
8338 m_spellImmune
[op
].erase(itr
);
8346 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8348 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8350 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8351 RemoveAurasWithDispelType(type
);
8354 float Unit::GetWeaponProcChance() const
8356 // normalized proc chance for weapon attack speed
8358 if(isAttackReady(BASE_ATTACK
))
8359 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8360 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8361 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8365 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8367 // proc per minute chance calculation
8368 if (PPM
<= 0) return 0.0f
;
8369 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8373 void Unit::Mount(uint32 mount
)
8378 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8380 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8382 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8385 if(GetTypeId() == TYPEID_PLAYER
)
8387 Pet
* pet
= GetPet();
8390 if(pet
->isControlled())
8392 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8393 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8396 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8399 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8403 void Unit::Unmount()
8408 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8410 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8411 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8413 // only resummon old pet if the player is already added to a map
8414 // this prevents adding a pet to a not created map which would otherwise cause a crash
8415 // (it could probably happen when logging in after a previous crash)
8416 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8418 Pet
* NewPet
= new Pet
;
8419 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8422 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8426 void Unit::SetInCombatWith(Unit
* enemy
)
8428 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8431 SetInCombatState(true);
8436 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8438 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8439 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8441 SetInCombatState(true);
8445 SetInCombatState(false);
8448 void Unit::SetInCombatState(bool PvP
)
8450 // only alive units can be in combat
8455 m_CombatTimer
= 5000;
8456 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8458 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8459 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8462 void Unit::ClearInCombat()
8465 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8467 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8468 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8470 // Player's state will be cleared in Player::UpdateContestedPvP
8471 if(GetTypeId()!=TYPEID_PLAYER
)
8472 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8475 bool Unit::isTargetableForAttack() const
8477 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8480 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8483 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8486 int32
Unit::ModifyHealth(int32 dVal
)
8493 int32 curHealth
= (int32
)GetHealth();
8495 int32 val
= dVal
+ curHealth
;
8502 int32 maxHealth
= (int32
)GetMaxHealth();
8507 gain
= val
- curHealth
;
8509 else if(curHealth
!= maxHealth
)
8511 SetHealth(maxHealth
);
8512 gain
= maxHealth
- curHealth
;
8518 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8525 int32 curPower
= (int32
)GetPower(power
);
8527 int32 val
= dVal
+ curPower
;
8534 int32 maxPower
= (int32
)GetMaxPower(power
);
8538 SetPower(power
,val
);
8539 gain
= val
- curPower
;
8541 else if(curPower
!= maxPower
)
8543 SetPower(power
,maxPower
);
8544 gain
= maxPower
- curPower
;
8550 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8555 // Always can see self
8559 // player visible for other player if not logout and at same transport
8560 // including case when player is out of world
8561 bool at_same_transport
=
8562 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8563 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8564 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8565 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8568 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8571 // forbidden to seen (at GM respawn command)
8572 if(m_Visibility
==VISIBILITY_RESPAWN
)
8575 // always seen by owner
8576 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8579 // Grid dead/alive checks
8580 if( u
->GetTypeId()==TYPEID_PLAYER
)
8582 // non visible at grid for any stealth state
8583 if(!IsVisibleInGridForPlayer((Player
*)u
))
8586 // if player is dead then he can't detect anyone in any cases
8592 // all dead creatures/players not visible for any creatures
8593 if(!u
->isAlive() || !isAlive())
8597 // different visible distance checks
8598 if(u
->isInFlight()) // what see player in flight
8600 // use object grey distance for all (only see objects any way)
8601 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8604 else if(!isAlive()) // distance for show body
8606 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8609 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8611 if(u
->GetTypeId()==TYPEID_PLAYER
)
8613 // Players far than max visible distance for player or not in our map are not visible too
8614 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8619 // Units far than max visible distance for creature or not in our map are not visible too
8620 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8624 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8626 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8627 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8630 else // distance for show creature
8632 // Units far than max visible distance for creature or not in our map are not visible too
8633 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8637 // Visible units, always are visible for all units, except for units under invisibility
8638 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8641 // GMs see any players, not higher GMs and all units
8642 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8644 if(GetTypeId() == TYPEID_PLAYER
)
8645 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8650 // non faction visibility non-breakable for non-GMs
8651 if (m_Visibility
== VISIBILITY_OFF
)
8655 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8657 // detectable invisibility case
8659 // Invisible units, always are visible for units under same invisibility type
8660 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8661 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8662 u
->canDetectInvisibilityOf(this) ||
8663 // Units that can detect invisibility always are visible for units that can be detected
8664 canDetectInvisibilityOf(u
) ))
8669 // special cases for always overwrite invisibility/stealth
8670 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8673 if (!u
->IsHostileTo(this))
8675 // 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)
8676 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8678 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8681 // else apply same rules as for hostile case (detecting check for stealth)
8687 // Hunter mark functionality
8688 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8689 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8690 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8693 // else apply detecting check for stealth
8696 // none other cases for detect invisibility, so invisible
8700 // else apply stealth detecting check
8703 // unit got in stealth in this moment and must ignore old detected state
8704 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8707 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8708 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8711 // NOW ONLY STEALTH CASE
8713 // stealth and detected and visible for some seconds
8714 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8717 //if in non-detect mode then invisible for unit
8723 // If is attacked then stealth is lost, some creature can use stealth too
8724 if( !getAttackers().empty() )
8727 // If there is collision rogue is seen regardless of level difference
8728 // TODO: check sizes in DB
8729 float distance
= GetDistance(u
);
8730 if (distance
< 0.24f
)
8733 //If a mob or player is stunned he will not be able to detect stealth
8734 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8737 // Creature can detect target only in aggro radius
8738 if(u
->GetTypeId() != TYPEID_PLAYER
)
8740 //Always invisible from back and out of aggro range
8741 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8747 //Always invisible from back
8748 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8753 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8754 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8756 //Calculation if target is in front
8758 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8759 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8761 //Visible distance is modified by
8762 //-Level Diff (every level diff = 1.0f in visible distance)
8763 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8765 //This allows to check talent tree and will add addition stealth dependent on used points)
8766 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8770 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8771 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8772 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8774 if(distance
> visibleDistance
)
8778 // Now check is target visible with LoS
8780 u
->GetPosition(ox
,oy
,oz
);
8781 return IsWithinLOS(ox
,oy
,oz
);
8784 void Unit::SetVisibility(UnitVisibility x
)
8792 if(GetTypeId()==TYPEID_PLAYER
)
8793 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8795 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8799 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8801 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8803 for(uint32 i
= 0; i
< 10; ++i
)
8805 if(((1 << i
) & mask
)==0)
8808 // find invisibility level
8809 uint32 invLevel
= 0;
8810 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8811 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8812 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8813 invLevel
= (*itr
)->GetModifier()->m_amount
;
8815 // find invisibility detect level
8816 uint32 detectLevel
= 0;
8817 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8818 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8819 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8820 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8822 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8824 detectLevel
= ((Player
*)this)->GetDrunkValue();
8827 if(invLevel
<= detectLevel
)
8835 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8837 int32 main_speed_mod
= 0;
8838 float stack_bonus
= 1.0f
;
8839 float non_stack_bonus
= 1.0f
;
8847 if (IsMounted()) // Use on mount auras
8849 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8850 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8851 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8855 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8856 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8857 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8865 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8868 case MOVE_SWIM_BACK
:
8872 if (IsMounted()) // Use on mount auras
8873 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8874 else // Use not mount (shapeshift for example) auras (should stack)
8875 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8876 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8877 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8880 case MOVE_FLIGHT_BACK
:
8883 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8887 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8888 // now we ready for speed calculation
8889 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8897 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8898 // TODO: possible affect only on MOVE_RUN
8899 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8901 // Use speed from aura
8902 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8903 if (speed
> max_speed
)
8912 // Apply strongest slow aura mod to speed
8913 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8915 speed
*=(100.0f
+ slow
)/100.0f
;
8916 SetSpeed(mtype
, speed
, forced
);
8919 float Unit::GetSpeed( UnitMoveType mtype
) const
8921 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8924 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8929 // Update speed only on change
8930 if (m_speed_rate
[mtype
] == rate
)
8933 m_speed_rate
[mtype
] = rate
;
8935 propagateSpeedChange();
8943 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8946 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8949 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8952 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8954 case MOVE_SWIM_BACK
:
8955 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8957 case MOVE_TURN_RATE
:
8958 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+2+4+4+4+4+4+4+4);
8961 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8963 case MOVE_FLIGHT_BACK
:
8964 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8966 case MOVE_PITCH_RATE
:
8967 data
.Initialize(MSG_MOVE_SET_PITCH_RATE
, 8+4+2+4+4+4+4+4+4+4);
8970 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8974 data
.append(GetPackGUID());
8975 data
<< uint32(0); // movement flags
8976 data
<< uint16(0); // unk flags
8977 data
<< uint32(getMSTime());
8978 data
<< float(GetPositionX());
8979 data
<< float(GetPositionY());
8980 data
<< float(GetPositionZ());
8981 data
<< float(GetOrientation());
8982 data
<< uint32(0); // fall time
8983 data
<< float(GetSpeed(mtype
));
8984 SendMessageToSet( &data
, true );
8988 if(GetTypeId() == TYPEID_PLAYER
)
8990 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8991 // and do it only for real sent packets and use run for run/mounted as client expected
8992 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8998 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
9001 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
9004 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
9007 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
9009 case MOVE_SWIM_BACK
:
9010 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
9012 case MOVE_TURN_RATE
:
9013 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
9016 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
9018 case MOVE_FLIGHT_BACK
:
9019 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
9021 case MOVE_PITCH_RATE
:
9022 data
.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE
, 16);
9025 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
9028 data
.append(GetPackGUID());
9029 data
<< (uint32
)0; // moveEvent, NUM_PMOVE_EVTS = 0x39
9030 if (mtype
== MOVE_RUN
)
9031 data
<< uint8(0); // new 2.1.0
9032 data
<< float(GetSpeed(mtype
));
9033 SendMessageToSet( &data
, true );
9035 if(Pet
* pet
= GetPet())
9036 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9039 void Unit::SetHover(bool on
)
9042 CastSpell(this,11010,true);
9044 RemoveAurasDueToSpell(11010);
9047 void Unit::setDeathState(DeathState s
)
9049 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9053 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9055 if(IsNonMeleeSpellCasted(false))
9056 InterruptNonMeleeSpells(false);
9061 RemoveAllAurasOnDeath();
9062 UnsummonAllTotems();
9064 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9065 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9066 // remove aurastates allowing special moves
9067 ClearAllReactives();
9068 ClearDiminishings();
9070 else if(s
== JUST_ALIVED
)
9072 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9075 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9077 //_ApplyAllAuraMods();
9082 /*########################################
9084 ######## AGGRO SYSTEM ########
9086 ########################################*/
9087 bool Unit::CanHaveThreatList() const
9089 // only creatures can have threat list
9090 if( GetTypeId() != TYPEID_UNIT
)
9093 // only alive units can have threat list
9097 // pets and totems can not have threat list
9098 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() || ((Creature
*)this)->isVehicle() )
9104 //======================================================================
9106 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9108 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9111 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9113 return threat
* m_threatModifier
[school
];
9116 //======================================================================
9118 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9120 // Only mobs can manage threat lists
9121 if(CanHaveThreatList())
9122 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9125 //======================================================================
9127 void Unit::DeleteThreatList()
9129 m_ThreatManager
.clearReferences();
9132 //======================================================================
9134 void Unit::TauntApply(Unit
* taunter
)
9136 assert(GetTypeId()== TYPEID_UNIT
);
9138 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9141 if(!CanHaveThreatList())
9144 Unit
*target
= getVictim();
9145 if(target
&& target
== taunter
)
9148 SetInFront(taunter
);
9149 if (((Creature
*)this)->AI())
9150 ((Creature
*)this)->AI()->AttackStart(taunter
);
9152 m_ThreatManager
.tauntApply(taunter
);
9155 //======================================================================
9157 void Unit::TauntFadeOut(Unit
*taunter
)
9159 assert(GetTypeId()== TYPEID_UNIT
);
9161 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9164 if(!CanHaveThreatList())
9167 Unit
*target
= getVictim();
9168 if(!target
|| target
!= taunter
)
9171 if(m_ThreatManager
.isThreatListEmpty())
9173 if(((Creature
*)this)->AI())
9174 ((Creature
*)this)->AI()->EnterEvadeMode();
9178 m_ThreatManager
.tauntFadeOut(taunter
);
9179 target
= m_ThreatManager
.getHostilTarget();
9181 if (target
&& target
!= taunter
)
9184 if (((Creature
*)this)->AI())
9185 ((Creature
*)this)->AI()->AttackStart(target
);
9189 //======================================================================
9191 bool Unit::SelectHostilTarget()
9193 //function provides main threat functionality
9194 //next-victim-selection algorithm and evade mode are called
9195 //threat list sorting etc.
9197 assert(GetTypeId()== TYPEID_UNIT
);
9198 Unit
* target
= NULL
;
9200 //This function only useful once AI has been initialized
9201 if (!((Creature
*)this)->AI())
9204 if(!m_ThreatManager
.isThreatListEmpty())
9206 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9208 target
= m_ThreatManager
.getHostilTarget();
9214 if(!hasUnitState(UNIT_STAT_STUNNED
))
9216 ((Creature
*)this)->AI()->AttackStart(target
);
9220 // no target but something prevent go to evade mode
9221 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9224 // last case when creature don't must go to evade mode:
9225 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9226 // for example at owner command to pet attack some far away creature
9227 // Note: creature not have targeted movement generator but have attacker in this case
9228 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9230 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9232 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9237 // enter in evade mode in other case
9238 ((Creature
*)this)->AI()->EnterEvadeMode();
9243 //======================================================================
9244 //======================================================================
9245 //======================================================================
9247 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9249 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9251 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9253 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9254 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9255 level
= spellProto
->maxLevel
;
9257 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9258 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9259 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9260 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9261 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9263 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9264 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9265 int32 value
= basePoints
+ randvalue
;
9267 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9268 value
+= (int32
)(comboDamage
* comboPoints
);
9270 if(Player
* modOwner
= GetSpellModOwner())
9272 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9273 switch(effect_index
)
9276 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9279 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9282 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9287 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9288 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9289 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9290 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9295 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9297 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9299 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9301 int32 minduration
= GetSpellDuration(spellProto
);
9302 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9306 if( minduration
!= -1 && minduration
!= maxduration
)
9307 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9309 duration
= minduration
;
9313 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9314 // Find total mod value (negative bonus)
9315 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9316 // Find max mod (negative bonus)
9317 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9319 int32 durationMod
= 0;
9320 // Select strongest negative mod
9321 if (durationMod_always
> durationMod_not_stack
)
9322 durationMod
= durationMod_not_stack
;
9324 durationMod
= durationMod_always
;
9326 if (durationMod
!= 0)
9327 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9329 if (duration
< 0) duration
= 0;
9335 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9337 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9339 if(i
->DRGroup
!= group
)
9343 return DIMINISHING_LEVEL_1
;
9346 return DIMINISHING_LEVEL_1
;
9348 // If last spell was casted more than 15 seconds ago - reset the count.
9349 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9351 i
->hitCount
= DIMINISHING_LEVEL_1
;
9352 return DIMINISHING_LEVEL_1
;
9354 // or else increase the count.
9357 return DiminishingLevels(i
->hitCount
);
9360 return DIMINISHING_LEVEL_1
;
9363 void Unit::IncrDiminishing(DiminishingGroup group
)
9365 // Checking for existing in the table
9366 bool IsExist
= false;
9367 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9369 if(i
->DRGroup
!= group
)
9373 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9380 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9383 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9385 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9388 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9389 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9391 // test pet/charm masters instead pets/charmeds
9392 Unit
const* targetOwner
= GetCharmerOrOwner();
9393 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9395 Unit
const* target
= targetOwner
? targetOwner
: this;
9396 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9398 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9404 // Some diminishings applies to mobs too (for example, Stun)
9405 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9407 DiminishingLevels diminish
= Level
;
9410 case DIMINISHING_LEVEL_1
: break;
9411 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9412 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9413 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9418 duration
= int32(duration
* mod
);
9421 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9423 // Checking for existing in the table
9424 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9426 if(i
->DRGroup
!= group
)
9429 i
->hitTime
= getMSTime();
9440 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9442 return ObjectAccessor::GetUnit(object
,guid
);
9445 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9447 return isVisibleForOrDetect(u
,false,inVisibleList
);
9450 uint32
Unit::GetCreatureType() const
9452 if(GetTypeId() == TYPEID_PLAYER
)
9454 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9455 if(ssEntry
&& ssEntry
->creatureType
> 0)
9456 return ssEntry
->creatureType
;
9458 return CREATURE_TYPE_HUMANOID
;
9461 return ((Creature
*)this)->GetCreatureInfo()->type
;
9464 /*#######################################
9466 ######## STAT SYSTEM ########
9468 #######################################*/
9470 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9472 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9474 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9480 switch(modifierType
)
9484 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9488 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9491 val
= (100.0f
+ amount
) / 100.0f
;
9492 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9499 if(!CanModifyStats())
9504 case UNIT_MOD_STAT_STRENGTH
:
9505 case UNIT_MOD_STAT_AGILITY
:
9506 case UNIT_MOD_STAT_STAMINA
:
9507 case UNIT_MOD_STAT_INTELLECT
:
9508 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9510 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9511 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9515 case UNIT_MOD_FOCUS
:
9516 case UNIT_MOD_ENERGY
:
9517 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9519 case UNIT_MOD_RESISTANCE_HOLY
:
9520 case UNIT_MOD_RESISTANCE_FIRE
:
9521 case UNIT_MOD_RESISTANCE_NATURE
:
9522 case UNIT_MOD_RESISTANCE_FROST
:
9523 case UNIT_MOD_RESISTANCE_SHADOW
:
9524 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9526 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9527 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9529 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9530 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9531 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9540 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9542 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9544 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9548 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9551 return m_auraModifiersGroup
[unitMod
][modifierType
];
9554 float Unit::GetTotalStatValue(Stats stat
) const
9556 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9558 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9561 // value = ((base_value * base_pct) + total_value) * total_pct
9562 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9563 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9564 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9565 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9570 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9572 if(unitMod
>= UNIT_MOD_END
)
9574 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9578 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9581 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9582 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9583 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9584 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9589 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9591 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9595 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9596 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9597 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9598 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9599 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9600 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9609 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9611 Stats stat
= STAT_STRENGTH
;
9615 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9616 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9617 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9618 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9619 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9628 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9630 Powers power
= POWER_MANA
;
9634 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9635 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9636 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9637 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9638 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9647 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9649 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9651 float val
= GetTotalAuraModValue(unitMod
);
9658 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9660 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9663 return m_weaponDamage
[attType
][type
];
9666 void Unit::SetLevel(uint32 lvl
)
9668 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9671 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9672 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9675 void Unit::SetHealth(uint32 val
)
9677 uint32 maxHealth
= GetMaxHealth();
9681 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9684 if(GetTypeId() == TYPEID_PLAYER
)
9686 if(((Player
*)this)->GetGroup())
9687 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9689 else if(((Creature
*)this)->isPet())
9691 Pet
*pet
= ((Pet
*)this);
9692 if(pet
->isControlled())
9694 Unit
*owner
= GetOwner();
9695 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9696 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9701 void Unit::SetMaxHealth(uint32 val
)
9703 uint32 health
= GetHealth();
9704 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9707 if(GetTypeId() == TYPEID_PLAYER
)
9709 if(((Player
*)this)->GetGroup())
9710 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9712 else if(((Creature
*)this)->isPet())
9714 Pet
*pet
= ((Pet
*)this);
9715 if(pet
->isControlled())
9717 Unit
*owner
= GetOwner();
9718 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9719 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9727 void Unit::SetPower(Powers power
, uint32 val
)
9729 if(GetPower(power
) == val
)
9732 uint32 maxPower
= GetMaxPower(power
);
9736 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9738 WorldPacket
data(SMSG_POWER_UPDATE
);
9739 data
.append(GetPackGUID());
9740 data
<< uint8(power
);
9741 data
<< uint32(val
);
9742 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9745 if(GetTypeId() == TYPEID_PLAYER
)
9747 if(((Player
*)this)->GetGroup())
9748 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9750 else if(((Creature
*)this)->isPet())
9752 Pet
*pet
= ((Pet
*)this);
9753 if(pet
->isControlled())
9755 Unit
*owner
= GetOwner();
9756 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9757 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9760 // Update the pet's character sheet with happiness damage bonus
9761 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9763 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9768 void Unit::SetMaxPower(Powers power
, uint32 val
)
9770 uint32 cur_power
= GetPower(power
);
9771 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9774 if(GetTypeId() == TYPEID_PLAYER
)
9776 if(((Player
*)this)->GetGroup())
9777 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9779 else if(((Creature
*)this)->isPet())
9781 Pet
*pet
= ((Pet
*)this);
9782 if(pet
->isControlled())
9784 Unit
*owner
= GetOwner();
9785 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9786 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9791 SetPower(power
, val
);
9794 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9796 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9799 if(GetTypeId() == TYPEID_PLAYER
)
9801 if(((Player
*)this)->GetGroup())
9802 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9804 else if(((Creature
*)this)->isPet())
9806 Pet
*pet
= ((Pet
*)this);
9807 if(pet
->isControlled())
9809 Unit
*owner
= GetOwner();
9810 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9811 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9816 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9818 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9821 if(GetTypeId() == TYPEID_PLAYER
)
9823 if(((Player
*)this)->GetGroup())
9824 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9826 else if(((Creature
*)this)->isPet())
9828 Pet
*pet
= ((Pet
*)this);
9829 if(pet
->isControlled())
9831 Unit
*owner
= GetOwner();
9832 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9833 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9838 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9840 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9842 tAuraProcTriggerDamage
.push_back(aura
);
9844 tAuraProcTriggerDamage
.remove(aura
);
9847 uint32
Unit::GetCreatePowers( Powers power
) const
9849 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9852 case POWER_MANA
: return GetCreateMana();
9853 case POWER_RAGE
: return 1000;
9854 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9855 case POWER_ENERGY
: return 100;
9856 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9857 case POWER_RUNIC_POWER
: return 1000;
9863 void Unit::AddToWorld()
9865 Object::AddToWorld();
9868 void Unit::RemoveFromWorld()
9873 RemoveNotOwnSingleTargetAuras();
9876 Object::RemoveFromWorld();
9879 void Unit::CleanupsBeforeDelete()
9881 if(m_uint32Values
) // only for fully created object
9883 InterruptNonMeleeSpells(true);
9884 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9886 ClearComboPointHolders();
9888 getHostilRefManager().setOnlineOfflineState(false);
9890 RemoveAllGameObjects();
9891 RemoveAllDynObjects();
9892 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9897 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9900 m_charmInfo
= new CharmInfo(charm
);
9904 CharmInfo::CharmInfo(Unit
* unit
)
9905 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9907 for(int i
=0; i
<4; ++i
)
9909 m_charmspells
[i
].spellId
= 0;
9910 m_charmspells
[i
].active
= ACT_DISABLED
;
9914 void CharmInfo::InitPetActionBar()
9916 // the first 3 SpellOrActions are attack, follow and stay
9917 for(uint32 i
= 0; i
< 3; i
++)
9919 PetActionBar
[i
].Type
= ACT_COMMAND
;
9920 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9922 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9923 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9925 for(uint32 i
=0; i
< 4; i
++)
9927 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9928 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9932 void CharmInfo::InitEmptyActionBar()
9934 for(uint32 x
= 1; x
< 10; ++x
)
9936 PetActionBar
[x
].Type
= ACT_PASSIVE
;
9937 PetActionBar
[x
].SpellOrAction
= 0;
9939 PetActionBar
[0].Type
= ACT_COMMAND
;
9940 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9943 void CharmInfo::InitPossessCreateSpells()
9945 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9948 InitEmptyActionBar(); //charm action bar
9950 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9952 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9953 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9955 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_PASSIVE
);
9959 void CharmInfo::InitCharmCreateSpells()
9961 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9963 InitEmptyActionBar();
9969 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9971 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9972 m_charmspells
[x
].spellId
= spellId
;
9977 if (IsPassiveSpell(spellId
))
9979 m_unit
->CastSpell(m_unit
, spellId
, true);
9980 m_charmspells
[x
].active
= ACT_PASSIVE
;
9984 ActiveStates newstate
;
9985 bool onlyselfcast
= true;
9986 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9988 if(!spellInfo
) onlyselfcast
= false;
9989 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9991 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9992 onlyselfcast
= false;
9995 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9996 newstate
= ACT_DISABLED
;
9998 newstate
= ACT_PASSIVE
;
10000 AddSpellToAB(0, spellId
, newstate
);
10005 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
10007 for(uint8 i
= 0; i
< 10; i
++)
10009 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_PASSIVE
) && PetActionBar
[i
].SpellOrAction
== oldid
)
10011 PetActionBar
[i
].SpellOrAction
= newid
;
10014 if(newstate
== ACT_DECIDE
)
10015 PetActionBar
[i
].Type
= ACT_DISABLED
;
10017 PetActionBar
[i
].Type
= newstate
;
10026 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
10028 if(IsPassiveSpell(spellid
))
10031 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
10033 if(spellid
== m_charmspells
[x
].spellId
)
10035 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
10040 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10042 m_petnumber
= petnumber
;
10044 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10046 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10049 bool Unit::isFrozen() const
10051 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10052 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10053 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10058 struct ProcTriggeredData
10060 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
10061 : triggeredByAura(_triggeredByAura
),
10062 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10063 cooldown(_cooldown
)
10066 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10067 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10068 uint32 cooldown
; // possible hidden cooldown
10071 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10073 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10075 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10077 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10078 ProcTriggeredList procTriggered
;
10080 AuraList
const& auras
= GetAurasByType(*aur
);
10081 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10087 uint32 cooldown
; // returned at next line
10088 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10091 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10094 // Handle effects proceed this time
10095 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10097 // Some auras can be deleted in function called in this loop (except first, ofc)
10098 // Until storing auras in std::multimap to hard check deleting by another way
10099 if(i
!= procTriggered
.begin())
10101 bool found
= false;
10102 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10103 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10104 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10106 if(itr
->second
==i
->triggeredByAura
)
10115 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
);
10116 sLog
.outError("It can be deleted one from early processed auras:");
10117 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10118 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10119 sLog
.outError(" <end of list>");
10124 /// this is aura triggering code call
10125 Aura
* triggeredByAura
= i
->triggeredByAura
;
10127 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10128 /// used in speedup code check before check aura existance.
10129 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10131 /// success in event proccesing
10132 /// used in speedup code check before check aura existance.
10133 bool casted
= false;
10135 /// process triggered code
10138 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10140 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10141 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10142 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10145 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10147 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10148 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10149 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10150 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10154 case SPELL_AURA_DUMMY
:
10156 uint32 effect
= triggeredByAura
->GetEffIndex();
10157 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10158 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10159 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10162 case SPELL_AURA_PRAYER_OF_MENDING
:
10164 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10165 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10167 casted
= HandleMeandingAuraProc(triggeredByAura
);
10170 case SPELL_AURA_MOD_HASTE
:
10172 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10173 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10174 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10177 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10179 // nothing do, just charges counter
10180 // but count only in case appropriate school damage
10181 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10184 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10186 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10187 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10188 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10193 // nothing do, just charges counter
10199 /// Update charge (aura can be removed by triggers)
10200 if(casted
&& triggeredByAuraWithCharges
)
10202 /// need re-found aura (can be dropped by triggers)
10203 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10204 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10205 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10207 if(itr
->second
== triggeredByAura
) // pointer still valid
10209 if(triggeredByAura
->m_procCharges
> 0)
10210 triggeredByAura
->m_procCharges
-= 1;
10212 triggeredByAura
->UpdateAuraCharges();
10219 /// Safely remove auras with zero charges
10220 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10223 if((*i
)->m_procCharges
== 0)
10225 RemoveAurasDueToSpell((*i
)->GetId());
10226 next
= auras
.begin();
10232 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10234 return SPELL_SCHOOL_MASK_NORMAL
;
10237 Player
* Unit::GetSpellModOwner()
10239 if(GetTypeId()==TYPEID_PLAYER
)
10240 return (Player
*)this;
10241 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10243 Unit
* owner
= GetOwner();
10244 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10245 return (Player
*)owner
;
10250 ///----------Pet responses methods-----------------
10251 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10253 Unit
*owner
= GetCharmerOrOwner();
10254 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10257 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10258 data
<< uint8(0); // cast count?
10259 data
<< uint32(spellid
);
10260 data
<< uint8(msg
);
10261 // uint32 for some reason
10262 // uint32 for some reason
10263 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10266 void Unit::SendPetActionFeedback (uint8 msg
)
10268 Unit
* owner
= GetOwner();
10269 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10272 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10273 data
<< uint8(msg
);
10274 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10277 void Unit::SendPetTalk (uint32 pettalk
)
10279 Unit
* owner
= GetOwner();
10280 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10283 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10284 data
<< uint64(GetGUID());
10285 data
<< uint32(pettalk
);
10286 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10289 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10291 Unit
* owner
= GetOwner();
10292 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10295 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10296 data
<< uint64(GetGUID());
10297 data
<< uint8(0x0); // flags (0x1, 0x2)
10298 data
<< uint32(spellid
);
10299 data
<< uint32(cooltime
);
10301 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10304 void Unit::SendPetClearCooldown (uint32 spellid
)
10306 Unit
* owner
= GetOwner();
10307 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10310 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10311 data
<< uint32(spellid
);
10312 data
<< uint64(GetGUID());
10313 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10316 void Unit::SendPetAIReaction(uint64 guid
)
10318 Unit
* owner
= GetOwner();
10319 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10322 WorldPacket
data(SMSG_AI_REACTION
, 12);
10323 data
<< uint64(guid
) << uint32(00000002);
10324 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10327 ///----------End of Pet responses methods----------
10329 void Unit::StopMoving()
10331 clearUnitState(UNIT_STAT_MOVING
);
10333 // send explicit stop packet
10334 // rely on vmaps here because for example stormwind is in air
10335 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10336 //if (fabs(GetPositionZ() - z) < 2.0f)
10337 // Relocate(GetPositionX(), GetPositionY(), z);
10338 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10340 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10342 // update position and orientation;
10344 BuildHeartBeatMsg(&data
);
10345 SendMessageToSet(&data
,false);
10348 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10352 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10355 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10357 GetMotionMaster()->MovementExpired(false);
10358 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10360 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10362 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10366 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10368 GetMotionMaster()->MovementExpired(false);
10370 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10372 // restore appropriate movement generator
10374 GetMotionMaster()->MoveChase(getVictim());
10376 GetMotionMaster()->Initialize();
10378 // attack caster if can
10379 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10380 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10381 ((Creature
*)this)->AI()->AttackStart(caster
);
10385 if (GetTypeId() == TYPEID_PLAYER
)
10386 ((Player
*)this)->SetClientControl(this, !apply
);
10389 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10393 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10395 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10397 GetMotionMaster()->MoveConfused();
10401 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10403 GetMotionMaster()->MovementExpired(false);
10405 if (GetTypeId() == TYPEID_UNIT
)
10407 // if in combat restore movement generator
10409 GetMotionMaster()->MoveChase(getVictim());
10413 if(GetTypeId() == TYPEID_PLAYER
)
10414 ((Player
*)this)->SetClientControl(this, !apply
);
10417 bool Unit::IsSitState() const
10419 uint8 s
= getStandState();
10420 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10421 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10422 s
== PLAYER_STATE_SIT
;
10425 bool Unit::IsStandState() const
10427 uint8 s
= getStandState();
10428 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10431 void Unit::SetStandState(uint8 state
)
10433 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10435 if (IsStandState())
10436 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10438 if(GetTypeId()==TYPEID_PLAYER
)
10440 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10441 data
<< (uint8
)state
;
10442 ((Player
*)this)->GetSession()->SendPacket(&data
);
10446 bool Unit::IsPolymorphed() const
10448 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10451 void Unit::SetDisplayId(uint32 modelId
)
10453 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10455 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10457 Pet
*pet
= ((Pet
*)this);
10458 if(!pet
->isControlled())
10460 Unit
*owner
= GetOwner();
10461 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10462 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10466 void Unit::ClearComboPointHolders()
10468 while(!m_ComboPointHolders
.empty())
10470 uint32 lowguid
= *m_ComboPointHolders
.begin();
10472 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10473 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10474 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10476 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10480 void Unit::ClearAllReactives()
10483 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10484 m_reactiveTimer
[i
] = 0;
10486 if (HasAuraState( AURA_STATE_DEFENSE
))
10487 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10488 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10489 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10490 if (HasAuraState( AURA_STATE_CRIT
))
10491 ModifyAuraState(AURA_STATE_CRIT
, false);
10492 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10493 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10495 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10496 ((Player
*)this)->ClearComboPoints();
10499 void Unit::UpdateReactives( uint32 p_time
)
10501 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10503 ReactiveType reactive
= ReactiveType(i
);
10505 if(!m_reactiveTimer
[reactive
])
10508 if ( m_reactiveTimer
[reactive
] <= p_time
)
10510 m_reactiveTimer
[reactive
] = 0;
10512 switch ( reactive
)
10514 case REACTIVE_DEFENSE
:
10515 if (HasAuraState(AURA_STATE_DEFENSE
))
10516 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10518 case REACTIVE_HUNTER_PARRY
:
10519 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10520 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10522 case REACTIVE_CRIT
:
10523 if (HasAuraState(AURA_STATE_CRIT
))
10524 ModifyAuraState(AURA_STATE_CRIT
, false);
10526 case REACTIVE_HUNTER_CRIT
:
10527 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10528 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10530 case REACTIVE_OVERPOWER
:
10531 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10532 ((Player
*)this)->ClearComboPoints();
10540 m_reactiveTimer
[reactive
] -= p_time
;
10545 Unit
* Unit::SelectNearbyTarget() const
10547 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10549 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10550 cell
.SetNoCreate();
10552 std::list
<Unit
*> targets
;
10555 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10556 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10558 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10559 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10561 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10562 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *GetMap());
10563 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *GetMap());
10566 // remove current target
10568 targets
.remove(getVictim());
10570 // remove not LoS targets
10571 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10573 if(!IsWithinLOSInMap(*tIter
))
10575 std::list
<Unit
*>::iterator tIter2
= tIter
;
10577 targets
.erase(tIter2
);
10583 // no appropriate targets
10584 if(targets
.empty())
10588 uint32 rIdx
= urand(0,targets
.size()-1);
10589 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10590 for(uint32 i
= 0; i
< rIdx
; ++i
)
10596 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10600 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10601 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10605 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10606 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10610 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10613 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10615 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10618 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10620 if (CastingTime
> 7000) CastingTime
= 7000;
10621 if (CastingTime
< 1500) CastingTime
= 1500;
10623 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10624 CastingTime
= 3500;
10626 int32 overTime
= 0;
10628 bool DirectDamage
= false;
10629 bool AreaEffect
= false;
10631 for ( uint32 i
=0; i
<3;i
++)
10633 switch ( spellProto
->Effect
[i
] )
10635 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10636 case SPELL_EFFECT_POWER_DRAIN
:
10637 case SPELL_EFFECT_HEALTH_LEECH
:
10638 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10639 case SPELL_EFFECT_POWER_BURN
:
10640 case SPELL_EFFECT_HEAL
:
10641 DirectDamage
= true;
10643 case SPELL_EFFECT_APPLY_AURA
:
10644 switch ( spellProto
->EffectApplyAuraName
[i
] )
10646 case SPELL_AURA_PERIODIC_DAMAGE
:
10647 case SPELL_AURA_PERIODIC_HEAL
:
10648 case SPELL_AURA_PERIODIC_LEECH
:
10649 if ( GetSpellDuration(spellProto
) )
10650 overTime
= GetSpellDuration(spellProto
);
10653 // -5% per additional effect
10661 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10665 // Combined Spells with Both Over Time and Direct Damage
10666 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10668 // mainly for DoTs which are 3500 here otherwise
10669 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10670 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10671 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10672 // Portion to Over Time
10673 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10675 if ( damagetype
== DOT
)
10676 CastingTime
= uint32(CastingTime
* PtOT
);
10677 else if ( PtOT
< 1.0f
)
10678 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10683 // Area Effect Spells receive only half of bonus
10687 // -5% of total per any additional effect
10688 for ( uint8 i
=0; i
<effects
; ++i
)
10690 if ( CastingTime
> 175 )
10692 CastingTime
-= 175;
10701 return CastingTime
;
10704 void Unit::UpdateAuraForGroup(uint8 slot
)
10706 if(GetTypeId() == TYPEID_PLAYER
)
10708 Player
* player
= (Player
*)this;
10709 if(player
->GetGroup())
10711 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10712 player
->SetAuraUpdateMask(slot
);
10715 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10717 Pet
*pet
= ((Pet
*)this);
10718 if(pet
->isControlled())
10720 Unit
*owner
= GetOwner();
10721 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10723 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10724 pet
->SetAuraUpdateMask(slot
);
10730 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10732 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10733 return float(GetAttackTime(attType
))/1000.0f
;
10735 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10737 return 2.4; // fist attack
10739 switch (Weapon
->GetProto()->InventoryType
)
10741 case INVTYPE_2HWEAPON
:
10743 case INVTYPE_RANGED
:
10744 case INVTYPE_RANGEDRIGHT
:
10745 case INVTYPE_THROWN
:
10747 case INVTYPE_WEAPON
:
10748 case INVTYPE_WEAPONMAINHAND
:
10749 case INVTYPE_WEAPONOFFHAND
:
10751 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10755 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10757 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10758 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10759 if ((*itr
)->GetId() == spell_id
)
10765 bool Unit::IsUnderLastManaUseEffect() const
10767 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10770 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10772 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10774 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10777 player
->SetContestedPvPTimer(30000);
10778 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10780 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10781 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10782 // call MoveInLineOfSight for nearby contested guards
10783 SetVisibility(GetVisibility());
10785 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10787 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10788 // call MoveInLineOfSight for nearby contested guards
10789 SetVisibility(GetVisibility());
10793 void Unit::AddPetAura(PetAura
const* petSpell
)
10795 m_petAuras
.insert(petSpell
);
10796 if(Pet
* pet
= GetPet())
10797 pet
->CastPetAura(petSpell
);
10800 void Unit::RemovePetAura(PetAura
const* petSpell
)
10802 m_petAuras
.erase(petSpell
);
10803 if(Pet
* pet
= GetPet())
10804 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10807 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10809 Pet
* pet
= new Pet(HUNTER_PET
);
10811 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10817 pet
->SetOwnerGUID(GetGUID());
10818 pet
->SetCreatorGUID(GetGUID());
10819 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, getFaction());
10820 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10822 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10823 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10825 if(!pet
->InitStatsForLevel(level
))
10827 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10832 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10833 // this enables pet details window (Shift+P)
10834 pet
->AIM_Initialize();
10835 pet
->InitPetCreateSpells();
10836 pet
->SetHealth(pet
->GetMaxHealth());
10841 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10843 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10845 if(!spellProcEvent
)
10847 // used to prevent spam in log about same non-handled spells
10848 static std::set
<uint32
> nonHandledSpellProcSet
;
10850 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10852 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10853 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10856 // spell.dbc use totally different flags, that only can create problems if used.
10860 // Check spellProcEvent data requirements
10861 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10864 // Check if current equipment allows aura to proc
10865 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10867 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10869 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10871 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10874 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10876 // Check if player is wearing shield
10877 Item
*item
= ((Player
*)this)->GetShield(true);
10878 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10883 float chance
= (float)spellProto
->procChance
;
10885 if(Player
* modOwner
= GetSpellModOwner())
10886 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10888 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10890 uint32 WeaponSpeed
= GetAttackTime(attType
);
10891 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10894 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10895 return roll_chance_f(chance
);
10898 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10900 // aura can be deleted at casts
10901 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10902 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10903 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10904 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10907 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10909 // current aura expire
10910 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10912 // next target selection
10913 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10916 if (spellProto
->EffectRadiusIndex
[effIdx
])
10917 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10919 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10921 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10923 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10925 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10927 // aura will applied from caster, but spell casted from current aura holder
10928 SpellModifier
*mod
= new SpellModifier
;
10929 mod
->op
= SPELLMOD_CHARGES
;
10930 mod
->value
= jumps
-5; // negative
10931 mod
->type
= SPELLMOD_FLAT
;
10932 mod
->spellId
= spellProto
->Id
;
10933 mod
->effectId
= effIdx
;
10934 mod
->lastAffected
= NULL
;
10935 mod
->mask
= spellProto
->SpellFamilyFlags
;
10938 caster
->AddSpellMod(mod
, true);
10939 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10940 caster
->AddSpellMod(mod
, false);
10946 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10950 void Unit::RemoveAurasAtChanneledTarget(SpellEntry
const* spellInfo
)
10952 uint64 target_guid
= GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
);
10954 if(!IS_UNIT_GUID(target_guid
))
10957 Unit
* target
= ObjectAccessor::GetUnit(*this, target_guid
);
10961 for (AuraMap::iterator iter
= target
->GetAuras().begin(); iter
!= target
->GetAuras().end(); )
10963 if (iter
->second
->GetId() == spellInfo
->Id
&& iter
->second
->GetCasterGUID()==GetGUID())
10964 target
->RemoveAura(iter
);