2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
49 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
53 1.25f
, // MOVE_WALKBACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIMBACK
56 3.141594f
, // MOVE_TURN
62 // auraTypes contains attacker auras capable of proc'ing cast auras
63 static Unit::AuraTypeSet
GenerateAttakerProcCastAuraTypes()
65 static Unit::AuraTypeSet auraTypes
;
66 auraTypes
.insert(SPELL_AURA_DUMMY
);
67 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
68 auraTypes
.insert(SPELL_AURA_MOD_HASTE
);
69 auraTypes
.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
73 // auraTypes contains victim auras capable of proc'ing cast auras
74 static Unit::AuraTypeSet
GenerateVictimProcCastAuraTypes()
76 static Unit::AuraTypeSet auraTypes
;
77 auraTypes
.insert(SPELL_AURA_DUMMY
);
78 auraTypes
.insert(SPELL_AURA_PRAYER_OF_MENDING
);
79 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
83 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
84 static Unit::AuraTypeSet
GenerateAttakerProcEffectAuraTypes()
86 static Unit::AuraTypeSet auraTypes
;
87 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_DONE
);
88 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
89 auraTypes
.insert(SPELL_AURA_MOD_CASTING_SPEED
);
90 auraTypes
.insert(SPELL_AURA_MOD_RATING
);
94 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
95 static Unit::AuraTypeSet
GenerateVictimProcEffectAuraTypes()
97 static Unit::AuraTypeSet auraTypes
;
98 auraTypes
.insert(SPELL_AURA_MOD_RESISTANCE
);
99 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
100 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
101 auraTypes
.insert(SPELL_AURA_MOD_BLOCK_PERCENT
);
102 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
106 static Unit::AuraTypeSet attackerProcCastAuraTypes
= GenerateAttakerProcCastAuraTypes();
107 static Unit::AuraTypeSet attackerProcEffectAuraTypes
= GenerateAttakerProcEffectAuraTypes();
109 static Unit::AuraTypeSet victimProcCastAuraTypes
= GenerateVictimProcCastAuraTypes();
110 static Unit::AuraTypeSet victimProcEffectAuraTypes
= GenerateVictimProcEffectAuraTypes();
112 // auraTypes contains auras capable of proc'ing for attacker and victim
113 static Unit::AuraTypeSet
GenerateProcAuraTypes()
115 Unit::AuraTypeSet auraTypes
;
116 auraTypes
.insert(attackerProcCastAuraTypes
.begin(),attackerProcCastAuraTypes
.end());
117 auraTypes
.insert(attackerProcEffectAuraTypes
.begin(),attackerProcEffectAuraTypes
.end());
118 auraTypes
.insert(victimProcCastAuraTypes
.begin(),victimProcCastAuraTypes
.end());
119 auraTypes
.insert(victimProcEffectAuraTypes
.begin(),victimProcEffectAuraTypes
.end());
123 static Unit::AuraTypeSet procAuraTypes
= GenerateProcAuraTypes();
125 bool IsPassiveStackableSpell( uint32 spellId
)
127 if(!IsPassiveSpell(spellId
))
130 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
134 for(int j
= 0; j
< 3; ++j
)
136 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
144 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
146 m_objectType
|= TYPEMASK_UNIT
;
147 m_objectTypeId
= TYPEID_UNIT
;
149 m_updateFlag
= (UPDATEFLAG_HIGHGUID
| UPDATEFLAG_LIVING
| UPDATEFLAG_HASPOSITION
);
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_AURAS
; ++i
)
188 m_visibleAuras
[i
] = 0;
189 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
190 m_spellImmune
[i
].clear();
191 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
193 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
194 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
195 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
196 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
198 // implement 50% base damage from offhand
199 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
201 for (int i
= 0; i
< 3; i
++)
203 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
204 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
206 for (int i
= 0; i
< MAX_STATS
; i
++)
207 m_createStats
[i
] = 0.0f
;
210 m_modMeleeHitChance
= 0.0f
;
211 m_modRangedHitChance
= 0.0f
;
212 m_modSpellHitChance
= 0.0f
;
213 m_baseSpellCritChance
= 5;
218 //m_victimThreat = 0.0f;
219 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
220 m_threatModifier
[i
] = 1.0f
;
222 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
223 m_speed_rate
[i
] = 1.0f
;
227 m_unit_movement_flags
= 0;
229 // remove aurastates allowing special moves
230 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
231 m_reactiveTimer
[i
] = 0;
236 // set current spells as deletable
237 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
239 if (m_currentSpells
[i
])
241 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
242 m_currentSpells
[i
] = NULL
;
246 RemoveAllGameObjects();
247 RemoveAllDynObjects();
249 if(m_charmInfo
) delete m_charmInfo
;
252 void Unit::Update( uint32 p_time
)
254 /*if(p_time > m_AurasCheck)
259 m_AurasCheck -= p_time;*/
261 // WARNING! Order of execution here is important, do not change.
262 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
263 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
264 m_Events
.Update( p_time
);
265 _UpdateSpells( p_time
);
267 // update combat timer only for players and pets
268 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
270 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
271 // targets without stopping half way there and running off.
272 // These flags are reset after target dies or another command is given.
273 if( m_HostilRefManager
.isEmpty() )
275 // m_CombatTimer set at aura start and it will be freeze until aura removing
276 if ( m_CombatTimer
<= p_time
)
279 m_CombatTimer
-= p_time
;
283 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
285 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
288 // update abilities available only for fraction of time
289 UpdateReactives( p_time
);
291 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, GetHealth() < GetMaxHealth()*0.20f
);
292 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, GetHealth() < GetMaxHealth()*0.35f
);
294 i_motionMaster
.UpdateMotion(p_time
);
297 bool Unit::haveOffhandWeapon() const
299 if(GetTypeId() == TYPEID_PLAYER
)
300 return ((Player
*)this)->GetWeaponForAttack(OFF_ATTACK
,true);
305 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player
* player
)
308 if(GetMotionMaster()->GetDestination(x
, y
, z
))
309 SendMonsterMoveWithSpeed(x
, y
, z
, GetUnitMovementFlags(), 0, player
);
312 void Unit::SendMonsterMoveWithSpeed(float x
, float y
, float z
, uint32 MovementFlags
, uint32 transitTime
, Player
* player
)
316 float dx
= x
- GetPositionX();
317 float dy
= y
- GetPositionY();
318 float dz
= z
- GetPositionZ();
320 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
326 double speed
= GetSpeed((MovementFlags
& MOVEMENTFLAG_WALK_MODE
) ? MOVE_WALK
: MOVE_RUN
);
330 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
332 //float orientation = (float)atan2((double)dy, (double)dx);
333 SendMonsterMove(x
, y
, z
, 0, MovementFlags
, transitTime
, player
);
336 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, uint32 MovementFlags
, uint32 Time
, Player
* player
)
338 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
339 data
.append(GetPackGUID());
341 // Point A, starting location
342 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
343 // unknown field - unrelated to orientation
344 // seems to increment about 1000 for every 1.7 seconds
345 // for now, we'll just use mstime
348 data
<< uint8(type
); // unknown
351 case 0: // normal packet
353 case 1: // stop packet
354 SendMessageToSet( &data
, true );
356 case 2: // not used currently
361 case 3: // not used currently
362 data
<< uint64(0); // probably target guid
364 case 4: // not used currently
365 data
<< float(0); // probably orientation
369 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
370 data
<< uint32(MovementFlags
);
372 data
<< Time
; // Time in between points
373 data
<< uint32(1); // 1 single waypoint
374 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
377 player
->GetSession()->SendPacket(&data
);
379 SendMessageToSet( &data
, true );
382 void Unit::SendMonsterMoveByPath(Path
const& path
, uint32 start
, uint32 end
, uint32 MovementFlags
)
384 uint32 traveltime
= uint32(path
.GetTotalLength(start
, end
) * 32);
386 uint32 pathSize
= end
-start
;
388 WorldPacket
data( SMSG_MONSTER_MOVE
, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize
*4*3) );
389 data
.append(GetPackGUID());
390 data
<< GetPositionX( )
393 data
<< GetOrientation( );
395 data
<< uint32( MovementFlags
);
396 data
<< uint32( traveltime
);
397 data
<< uint32( pathSize
);
398 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
400 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
401 SendMessageToSet(&data
, true);
404 void Unit::resetAttackTimer(WeaponAttackType type
)
406 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
409 bool Unit::canReachWithAttack(Unit
*pVictim
) const
412 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
415 return IsWithinDistInMap(pVictim
, reach
);
418 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
420 if (auraType
>= TOTAL_AURAS
) return;
421 AuraList::iterator iter
, next
;
422 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
429 RemoveAurasDueToSpell((*iter
)->GetId());
430 if (!m_modAuras
[auraType
].empty())
431 next
= m_modAuras
[auraType
].begin();
438 bool Unit::HasAuraType(AuraType auraType
) const
440 return (!m_modAuras
[auraType
].empty());
443 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
444 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
446 if(!HasAuraType(auraType
))
449 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
450 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
451 float chance
= float(damage
) / max_dmg
* 100.0f
;
452 if (roll_chance_f(chance
))
453 RemoveSpellsCausingAura(auraType
);
456 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
458 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
461 //You don't lose health from damage taken from another player while in a sanctuary
462 //You still see it in the combat log though
463 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
465 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
466 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
470 // remove affects from victim (including from 0 damage and DoTs)
472 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
474 // remove affects from attacker at any non-DoT damage (including 0 damage)
475 if( damagetype
!= DOT
)
477 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
478 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
481 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
483 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
484 pVictim
->SetStandState(PLAYER_STATE_NONE
);
487 //Script Event damage Deal
488 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
489 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
490 //Script Event damage taken
491 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
492 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
496 // Rage from physical damage received .
497 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
498 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
503 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
504 // root type spells do not dispell the root effect
505 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
506 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
508 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
510 // no xp,health if type 8 /critters/
511 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
513 pVictim
->setDeathState(JUST_DIED
);
514 pVictim
->SetHealth(0);
516 // allow loot only if has loot_id in creature_template
517 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
518 if(cInfo
&& cInfo
->lootid
)
519 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
521 // some critters required for quests
522 if(GetTypeId() == TYPEID_PLAYER
)
523 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
528 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
529 ((Creature
*)pVictim
)->AI()->AttackStart(this);
532 DEBUG_LOG("DealDamageStart");
534 uint32 health
= pVictim
->GetHealth();
535 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
537 // duel ends when player has 1 or less hp
538 bool duel_hasEnded
= false;
539 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
541 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
542 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
545 duel_hasEnded
= true;
548 if(pVictim
!= this && damagetype
!= DOT
)
550 SetInCombatWith(pVictim
);
551 pVictim
->SetInCombatWith(this);
553 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
554 SetContestedPvP(attackedPlayer
);
557 // Rage from Damage made (only from direct weapon damage)
558 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
560 uint32 weaponSpeedHitFactor
;
562 switch(cleanDamage
->attackType
)
566 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
567 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
569 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
571 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
577 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
578 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
580 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
582 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
591 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
593 if(((Player
*)pVictim
)->InBattleGround())
595 Player
*killer
= ((Player
*)this);
596 if(killer
!= ((Player
*)pVictim
))
597 if(BattleGround
*bg
= killer
->GetBattleGround())
598 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
602 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
603 ((Creature
*)pVictim
)->SetLootRecipient(this);
604 if (health
<= damage
)
606 // battleground things
607 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
609 Player
*killed
= ((Player
*)pVictim
);
610 Player
*killer
= NULL
;
611 if(GetTypeId() == TYPEID_PLAYER
)
612 killer
= ((Player
*)this);
613 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
615 Unit
*owner
= GetOwner();
616 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
617 killer
= ((Player
*)owner
);
621 if(BattleGround
*bg
= killed
->GetBattleGround())
622 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
625 DEBUG_LOG("DealDamage: victim just died");
627 // find player: owner of controlled `this` or `this` itself maybe
628 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
630 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
631 player
= ((Creature
*)pVictim
)->GetLootRecipient();
632 // Reward player, his pets, and group/raid members
633 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
634 if(player
&& player
!=pVictim
)
635 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
636 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
638 DEBUG_LOG("DealDamageAttackStop");
641 pVictim
->CombatStop();
642 pVictim
->getHostilRefManager().deleteReferences();
644 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
646 // if talent known but not triggered (check priest class for speedup check)
647 Aura
* spiritOfRedemtionTalentReady
= NULL
;
648 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
649 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
651 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
652 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
654 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
656 spiritOfRedemtionTalentReady
= *itr
;
662 DEBUG_LOG("SET JUST_DIED");
663 if(!spiritOfRedemtionTalentReady
)
664 pVictim
->setDeathState(JUST_DIED
);
666 DEBUG_LOG("DealDamageHealth1");
668 if(spiritOfRedemtionTalentReady
)
670 // save value before aura remove
671 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
673 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
675 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
676 pVictim
->RemoveAllAurasOnDeath();
678 // restore for use at real death
679 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
681 // FORM_SPIRITOFREDEMPTION and related auras
682 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
685 pVictim
->SetHealth(0);
687 // remember victim PvP death for corpse type and corpse reclaim delay
688 // at original death (not at SpiritOfRedemtionTalent timeout)
689 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
690 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
692 // Call KilledUnit for creatures
693 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
694 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
697 if ( pVictim
->GetTypeId() == TYPEID_PLAYER
)
699 if(GetTypeId() == TYPEID_UNIT
)
700 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
, GetEntry());
701 else if(GetTypeId() == TYPEID_PLAYER
)
702 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
, 1);
705 // 10% durability loss on death
706 // clean InHateListOf
707 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
709 // only if not player and not controlled by player pet. And not at BG
710 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
712 DEBUG_LOG("We are dead, loosing 10 percents durability");
713 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
714 // durability lost message
715 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
716 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
719 else // creature died
721 DEBUG_LOG("DealDamageNotPlayer");
722 Creature
*cVictim
= (Creature
*)pVictim
;
724 if(!cVictim
->isPet())
726 cVictim
->DeleteThreatList();
727 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
729 // Call creature just died function
731 cVictim
->AI()->JustDied(this);
733 // Dungeon specific stuff, only applies to players killing creatures
734 if(cVictim
->GetInstanceId())
736 Map
*m
= cVictim
->GetMap();
737 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
738 // TODO: do instance binding anyway if the charmer/owner is offline
740 if(m
->IsDungeon() && creditedPlayer
)
742 if(m
->IsRaid() || m
->IsHeroic())
744 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
745 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
749 // the reset time is set but not added to the scheduler
750 // until the players leave the instance
751 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
752 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
753 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
759 // last damage from non duel opponent or opponent controlled creature
762 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
763 Player
*he
= (Player
*)pVictim
;
767 he
->duel
->opponent
->CombatStopWithPets(true);
768 he
->CombatStopWithPets(true);
770 he
->DuelComplete(DUEL_INTERUPTED
);
773 else // if (health <= damage)
775 DEBUG_LOG("DealDamageAlive");
777 pVictim
->ModifyHealth(- (int32
)damage
);
779 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
780 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
782 uint32 procVictim
= PROC_FLAG_NONE
;
784 // if just dropped below 20% (for CheatDeath)
785 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
786 procVictim
= PROC_FLAG_LOW_HEALTH
;
788 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
791 if(damagetype
!= DOT
)
795 // if have target and damage pVictim just call AI recation
796 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
797 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
801 // if not have main target then attack state with target (including AI call)
802 //start melee attacks only after melee hit
803 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
807 // polymorphed and other negative transformed cases
808 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
809 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
811 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
812 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
814 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
816 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
817 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
819 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
821 else // victim is a player
823 // Rage from damage received
824 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
826 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
827 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
830 // random durability for items (HIT TAKEN)
831 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
833 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
834 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
838 if(GetTypeId()==TYPEID_PLAYER
)
840 // random durability for items (HIT DONE)
841 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
843 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
844 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
848 // TODO: Store auras by interrupt flag to speed this up.
849 AuraMap
& vAuras
= pVictim
->GetAuras();
850 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
852 const SpellEntry
*se
= i
->second
->GetSpellProto();
854 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
857 if (se
->procFlags
& (1<<3))
859 if (!roll_chance_i(se
->procChance
))
864 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
865 // FIXME: this may cause the auras with proc chance to be rerolled several times
866 next
= vAuras
.begin();
871 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
873 if( damagetype
!= DOT
)
875 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
877 // skip channeled spell (processed differently below)
878 if (i
== CURRENT_CHANNELED_SPELL
)
881 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
882 if(spell
->getState() == SPELL_STATE_PREPARING
)
887 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
889 if (spell
->getState() == SPELL_STATE_CASTING
)
891 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
892 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
894 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
895 spell
->DelayedChannel();
897 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
899 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
900 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
903 else if (spell
->getState() == SPELL_STATE_DELAYED
)
904 // break channeled spell in delayed state on damage
906 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
907 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
912 // last damage from duel opponent
915 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
916 Player
*he
= (Player
*)pVictim
;
922 he
->duel
->opponent
->CombatStopWithPets(true);
923 he
->CombatStopWithPets(true);
925 he
->CastSpell(he
, 7267, true); // beg
926 he
->DuelComplete(DUEL_WON
);
930 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
935 void Unit::CastStop(uint32 except_spellid
)
937 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
938 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
939 InterruptSpell(i
,false);
942 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
944 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
948 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
952 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
955 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
959 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
964 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
966 if(!originalCaster
&& triggredByAura
)
967 originalCaster
= triggredByAura
->GetCasterGUID();
969 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
971 SpellCastTargets targets
;
972 targets
.setUnitTarget( Victim
);
973 spell
->m_CastItem
= castItem
;
974 spell
->prepare(&targets
, triggredByAura
);
977 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
979 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
983 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
987 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggredByAura
, originalCaster
);
990 void Unit::CastCustomSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
994 sLog
.outError("CastCustomSpell: unknown spell");
999 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1001 if(!originalCaster
&& triggredByAura
)
1002 originalCaster
= triggredByAura
->GetCasterGUID();
1004 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1007 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
1010 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1013 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1015 SpellCastTargets targets
;
1016 targets
.setUnitTarget( Victim
);
1017 spell
->m_CastItem
= castItem
;
1018 spell
->prepare(&targets
, triggredByAura
);
1021 // used for scripting
1022 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
1024 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1028 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()));
1032 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
1035 // used for scripting
1036 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
1040 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1045 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1047 if(!originalCaster
&& triggredByAura
)
1048 originalCaster
= triggredByAura
->GetCasterGUID();
1050 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1052 SpellCastTargets targets
;
1053 targets
.setDestination(x
, y
, z
);
1054 spell
->m_CastItem
= castItem
;
1055 spell
->prepare(&targets
, triggredByAura
);
1058 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1060 // TODO this in only generic way, check for exceptions
1061 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1063 // Per-damage calss calculation
1064 switch (spellInfo
->DmgClass
)
1066 // Melee and Ranged Spells
1067 case SPELL_DAMAGE_CLASS_RANGED
:
1068 case SPELL_DAMAGE_CLASS_MELEE
:
1070 // Calculate physical outcome
1071 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1073 //Used to store the Hit Outcome
1074 cleanDamage
->hitOutCome
= outcome
;
1076 // Return miss/evade first (sends miss message)
1079 case MELEE_HIT_EVADE
:
1081 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1085 case MELEE_HIT_MISS
:
1087 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1090 if(GetTypeId()== TYPEID_PLAYER
)
1091 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1093 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1098 // Hitinfo, Victimstate
1099 uint32 hitInfo
= HITINFO_NORMALSWING
;
1100 VictimState victimState
= VICTIMSTATE_NORMAL
;
1103 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1105 uint32 modDamage
=*damage
;
1107 // apply spellmod to Done damage
1108 if(Player
* modOwner
= GetSpellModOwner())
1109 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1111 //Calculate armor mitigation
1112 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1114 // random durability for main hand weapon (ABSORB)
1115 if(damageAfterArmor
< *damage
)
1116 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1117 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1118 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1120 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1121 *damage
= damageAfterArmor
;
1126 // Calculate damage bonus
1127 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1133 case MELEE_HIT_BLOCK_CRIT
:
1134 case MELEE_HIT_CRIT
:
1136 uint32 bonusDmg
= *damage
;
1138 // Apply crit_damage bonus
1139 if(Player
* modOwner
= GetSpellModOwner())
1140 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1142 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1143 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1144 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1145 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1146 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1148 *damage
+= bonusDmg
;
1150 // Resilience - reduce crit damage
1151 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1153 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1154 cleanDamage
->damage
+= resilienceReduction
;
1155 *damage
-= resilienceReduction
;
1159 hitInfo
|= HITINFO_CRITICALHIT
;
1161 ModifyAuraState(AURA_STATE_CRIT
, true);
1162 StartReactiveTimer( REACTIVE_CRIT
);
1164 if(getClass()==CLASS_HUNTER
)
1166 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1167 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1170 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1172 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1173 if (blocked_amount
>= *damage
)
1175 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1176 victimState
= VICTIMSTATE_BLOCKS
;
1177 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1182 // To Help Calculate Rage
1183 cleanDamage
->damage
+= blocked_amount
;
1184 *damage
= *damage
- blocked_amount
;
1187 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1188 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1190 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1193 ((Player
*)pVictim
)->UpdateDefense();
1195 // random durability for main hand weapon (BLOCK)
1196 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1197 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1202 case MELEE_HIT_PARRY
:
1204 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1206 victimState
= VICTIMSTATE_PARRY
;
1208 // Counter-attack ( explained in Unit::DoAttackDamage() )
1209 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1211 // Get attack timers
1212 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1213 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1215 // Reduce attack time
1216 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1218 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1219 float percent60
= 3 * percent20
;
1220 if(offtime
> percent20
&& offtime
<= percent60
)
1222 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1224 else if(offtime
> percent60
)
1226 offtime
-= 2 * percent20
;
1227 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1232 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1233 float percent60
= 3 * percent20
;
1234 if(basetime
> percent20
&& basetime
<= percent60
)
1236 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1238 else if(basetime
> percent60
)
1240 basetime
-= 2 * percent20
;
1241 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1246 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1248 // Update victim defense ?
1249 ((Player
*)pVictim
)->UpdateDefense();
1251 // random durability for main hand weapon (PARRY)
1252 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1253 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1257 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1259 // Mongoose bite - set only Counterattack here
1260 if (pVictim
->getClass() == CLASS_HUNTER
)
1262 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1263 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1267 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1268 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1272 case MELEE_HIT_DODGE
:
1274 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1275 ((Player
*)pVictim
)->UpdateDefense();
1277 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1279 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1280 victimState
= VICTIMSTATE_DODGE
;
1283 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1286 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1288 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1289 StartReactiveTimer( REACTIVE_OVERPOWER
);
1293 if (pVictim
->getClass() != CLASS_ROGUE
)
1295 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1296 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1300 case MELEE_HIT_BLOCK
:
1302 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1303 if (blocked_amount
>= *damage
)
1305 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1306 victimState
= VICTIMSTATE_BLOCKS
;
1307 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1312 // To Help Calculate Rage
1313 cleanDamage
->damage
+= blocked_amount
;
1314 *damage
= *damage
- blocked_amount
;
1317 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1318 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1320 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1323 ((Player
*)pVictim
)->UpdateDefense();
1325 // random durability for main hand weapon (BLOCK)
1326 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1327 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1331 case MELEE_HIT_EVADE
: // already processed early
1332 case MELEE_HIT_MISS
: // already processed early
1333 case MELEE_HIT_GLANCING
:
1334 case MELEE_HIT_CRUSHING
:
1335 case MELEE_HIT_NORMAL
:
1339 // do all damage=0 cases here
1341 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1346 case SPELL_DAMAGE_CLASS_NONE
:
1347 case SPELL_DAMAGE_CLASS_MAGIC
:
1349 // Calculate damage bonus
1350 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1352 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1355 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1357 // Resilience - reduce crit damage
1358 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1360 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1361 if(*damage
> damage_reduction
)
1362 *damage
-= damage_reduction
;
1367 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1369 // spell proc all magic damage==0 case in this function
1373 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1374 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1376 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1383 // TODO this in only generic way, check for exceptions
1384 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1387 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1389 if(!this || !pVictim
)
1391 if(!this->isAlive() || !pVictim
->isAlive())
1394 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1398 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1402 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1404 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1407 // Calculate absorb & resists
1411 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1413 //No more damage left, target absorbed and/or resisted all damage
1414 if (damage
> absorb
+ resist
)
1415 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1418 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1421 HitInfo
|= HITINFO_ABSORB
;
1424 HitInfo
|= HITINFO_RESIST
;
1425 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1429 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1434 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1437 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1438 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1440 // Actual log sent to client
1441 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1444 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1445 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1449 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1450 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1453 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1459 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1462 if(cleanDamage
.damage
)
1463 // Rage from damage received.
1464 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1465 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1471 void Unit::HandleEmoteCommand(uint32 anim_id
)
1473 WorldPacket
data( SMSG_EMOTE
, 12 );
1474 data
<< uint32(anim_id
);
1475 data
<< uint64(GetGUID());
1476 SendMessageToSet(&data
, true);
1479 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1481 uint32 newdamage
= 0;
1482 float armor
= pVictim
->GetArmor();
1483 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1484 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1486 if (armor
<0.0f
) armor
=0.0f
;
1488 float tmpvalue
= 0.0f
;
1489 if(getLevel() <= 59) //Level 1-59
1490 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1491 else if(getLevel() < 70) //Level 60-69
1492 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1494 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1498 if(tmpvalue
> 0.75f
)
1500 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1502 return (newdamage
> 1) ? newdamage
: 1;
1505 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1507 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1510 // Magic damage, check for resists
1511 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1513 // Get base victim resistance for school
1514 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1515 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1516 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1518 tmpvalue2
*= (float)(0.15f
/ getLevel());
1519 if (tmpvalue2
< 0.0f
)
1521 if (tmpvalue2
> 0.75f
)
1523 uint32 ran
= urand(0, 100);
1524 uint32 faq
[4] = {24,6,4,6};
1527 for (uint8 i
= 0; i
< 4; i
++)
1529 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1535 if (damagetype
== DOT
&& m
== 4)
1536 *resist
+= uint32(damage
- 1);
1538 *resist
+= uint32(damage
* m
/ 4);
1539 if(*resist
> damage
)
1545 int32 RemainingDamage
= damage
- *resist
;
1547 // absorb without mana cost
1548 int32 reflectDamage
= 0;
1549 Aura
* reflectAura
= NULL
;
1550 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1551 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1555 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1559 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1561 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1563 if (pVictim
->GetHealth() <= RemainingDamage
)
1565 int32 chance
= (*i
)->GetModifier()->m_amount
;
1566 if (roll_chance_i(chance
))
1568 pVictim
->CastSpell(pVictim
,31231,true);
1569 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1571 // with health > 10% lost health until health==10%, in other case no losses
1572 uint32 health10
= pVictim
->GetMaxHealth()/10;
1573 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1579 int32 currentAbsorb
;
1582 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1584 if(Unit
* caster
= (*i
)->GetCaster())
1586 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1587 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1589 switch((*k
)->GetModifier()->m_miscvalue
)
1591 case 5065: // Rank 1
1592 case 5064: // Rank 2
1593 case 5063: // Rank 3
1594 case 5062: // Rank 4
1595 case 5061: // Rank 5
1597 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1598 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1600 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1613 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1615 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1616 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1617 next
= vSchoolAbsorb
.begin();
1621 currentAbsorb
= RemainingDamage
;
1622 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1625 RemainingDamage
-= currentAbsorb
;
1627 // do not cast spells while looping auras; auras can get invalid otherwise
1629 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1631 // absorb by mana cost
1632 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1633 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1637 // check damage school mask
1638 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1641 int32 currentAbsorb
;
1642 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1643 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1645 currentAbsorb
= RemainingDamage
;
1647 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1648 if(Player
*modOwner
= GetSpellModOwner())
1649 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1651 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1652 if (currentAbsorb
> maxAbsorb
)
1653 currentAbsorb
= maxAbsorb
;
1655 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1656 if((*i
)->GetModifier()->m_amount
<= 0)
1658 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1659 next
= vManaShield
.begin();
1662 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1663 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1665 RemainingDamage
-= currentAbsorb
;
1668 // only split damage if not damaging yourself
1671 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1672 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1676 // check damage school mask
1677 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1680 // Damage can be splitted only if aura has an alive caster
1681 Unit
*caster
= (*i
)->GetCaster();
1682 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1685 int32 currentAbsorb
;
1686 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1687 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1689 currentAbsorb
= RemainingDamage
;
1691 RemainingDamage
-= currentAbsorb
;
1693 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1695 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1696 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1699 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1700 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1704 // check damage school mask
1705 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1708 // Damage can be splitted only if aura has an alive caster
1709 Unit
*caster
= (*i
)->GetCaster();
1710 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1713 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1715 RemainingDamage
-= splitted
;
1717 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1719 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1720 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1724 *absorb
= damage
- RemainingDamage
- *resist
;
1727 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
)
1729 MeleeHitOutcome outcome
;
1731 // If is casted Melee spell, calculate like physical
1733 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1735 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1737 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1738 pVictim
->AddThreat(this, 0.0f
);
1741 case MELEE_HIT_EVADE
:
1743 *hitInfo
|= HITINFO_MISS
;
1745 cleanDamage
->damage
= 0;
1748 case MELEE_HIT_MISS
:
1750 *hitInfo
|= HITINFO_MISS
;
1752 cleanDamage
->damage
= 0;
1753 if(GetTypeId()== TYPEID_PLAYER
)
1754 ((Player
*)this)->UpdateWeaponSkill(attType
);
1759 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1760 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1761 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1763 // -probability is between 0% and 40%
1765 float Probability
= 20;
1767 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1768 if( pVictim
->getLevel() < 30 )
1769 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1771 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1772 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1774 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1776 if(Probability
> 40.0f
)
1777 Probability
= 40.0f
;
1779 if(roll_chance_f(Probability
))
1780 CastSpell(pVictim
, 1604, true);
1783 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1784 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1786 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1788 // random durability for main hand weapon (ABSORB)
1789 if(damageAfterArmor
< *damage
)
1790 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1791 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1792 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1794 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1795 *damage
= damageAfterArmor
;
1798 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1799 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1801 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1802 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1806 case MELEE_HIT_BLOCK_CRIT
:
1807 case MELEE_HIT_CRIT
:
1809 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| HITINFO_UNK2
;
1813 crit_bonus
= *damage
;
1815 // Apply crit_damage bonus for melee spells
1818 if(Player
* modOwner
= GetSpellModOwner())
1819 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1821 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1822 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1823 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1824 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1825 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1828 *damage
+= crit_bonus
;
1830 uint32 resilienceReduction
= 0;
1832 if(attType
== RANGED_ATTACK
)
1834 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1835 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1836 // Resilience - reduce crit damage
1837 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1838 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1842 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1843 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1844 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1845 // Resilience - reduce crit damage
1846 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1847 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1850 *damage
-= resilienceReduction
;
1851 cleanDamage
->damage
+= resilienceReduction
;
1853 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1854 ((Player
*)this)->UpdateWeaponSkill(attType
);
1856 ModifyAuraState(AURA_STATE_CRIT
, true);
1857 StartReactiveTimer( REACTIVE_CRIT
);
1859 if(getClass()==CLASS_HUNTER
)
1861 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1862 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1865 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1867 *blocked_amount
= pVictim
->GetShieldBlockValue();
1869 if (pVictim
->GetUnitBlockChance())
1870 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1872 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1874 //Only set VICTIMSTATE_BLOCK on a full block
1875 if (*blocked_amount
>= uint32(*damage
))
1877 *victimState
= VICTIMSTATE_BLOCKS
;
1878 *blocked_amount
= uint32(*damage
);
1881 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1884 ((Player
*)pVictim
)->UpdateDefense();
1886 // random durability for main hand weapon (BLOCK)
1887 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1888 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1891 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1892 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1896 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1899 case MELEE_HIT_PARRY
:
1901 if(attType
== RANGED_ATTACK
) //range attack - no parry
1903 outcome
= MELEE_HIT_NORMAL
;
1907 cleanDamage
->damage
+= *damage
;
1909 *victimState
= VICTIMSTATE_PARRY
;
1911 // instant (maybe with small delay) counter attack
1913 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1914 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1916 // after parry nearest next attack time will reduced at %40 from full attack time.
1917 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1918 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1920 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1921 float percent60
= 3*percent20
;
1922 // set to 20% if in range 20%...20+40% of full time
1923 if(offtime
> percent20
&& offtime
<= percent60
)
1925 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1927 // decrease at %40 from full time
1928 else if(offtime
> percent60
)
1930 offtime
-= 2*percent20
;
1931 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1937 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1938 float percent60
= 3*percent20
;
1939 // set to 20% if in range 20%...20+40% of full time
1940 if(basetime
> percent20
&& basetime
<= percent60
)
1942 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1944 // decrease at %40 from full time
1945 else if(basetime
> percent60
)
1947 basetime
-= 2*percent20
;
1948 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1954 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1956 // Update victim defense ?
1957 ((Player
*)pVictim
)->UpdateDefense();
1959 // random durability for main hand weapon (PARRY)
1960 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1961 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1964 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1966 if (pVictim
->getClass() == CLASS_HUNTER
)
1968 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1969 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1973 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1974 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1977 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1980 case MELEE_HIT_DODGE
:
1982 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1984 outcome
= MELEE_HIT_NORMAL
;
1988 cleanDamage
->damage
+= *damage
;
1990 *victimState
= VICTIMSTATE_DODGE
;
1992 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1993 ((Player
*)pVictim
)->UpdateDefense();
1995 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1997 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1999 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
2000 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2004 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
2006 ((Player
*)this)->AddComboPoints(pVictim
, 1);
2007 StartReactiveTimer( REACTIVE_OVERPOWER
);
2010 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2013 case MELEE_HIT_BLOCK
:
2015 *blocked_amount
= pVictim
->GetShieldBlockValue();
2017 if (pVictim
->GetUnitBlockChance())
2018 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2020 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2022 //Only set VICTIMSTATE_BLOCK on a full block
2023 if (*blocked_amount
>= uint32(*damage
))
2025 *victimState
= VICTIMSTATE_BLOCKS
;
2026 *blocked_amount
= uint32(*damage
);
2029 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2032 ((Player
*)pVictim
)->UpdateDefense();
2034 // random durability for main hand weapon (BLOCK)
2035 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2036 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2039 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2040 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2044 case MELEE_HIT_GLANCING
:
2046 float reducePercent
= 1.0f
; //damage factor
2048 // calculate base values and mods
2049 float baseLowEnd
= 1.3;
2050 float baseHighEnd
= 1.2;
2051 switch(getClass()) // lowering base values for casters
2063 float maxLowEnd
= 0.6;
2064 switch(getClass()) // upper for melee classes
2068 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2072 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2073 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2074 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2076 // apply max/min bounds
2077 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2079 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2082 if ( highEnd
< 0.2f
) //high end limits
2084 if ( highEnd
> 0.99f
)
2087 if(lowEnd
> highEnd
) // prevent negative range size
2090 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2092 *damage
= uint32(reducePercent
* *damage
);
2093 cleanDamage
->damage
+= *damage
;
2094 *hitInfo
|= HITINFO_GLANCING
;
2097 case MELEE_HIT_CRUSHING
:
2099 // 150% normal damage
2100 *damage
+= (*damage
/ 2);
2101 cleanDamage
->damage
= *damage
;
2102 *hitInfo
|= HITINFO_CRUSHING
;
2103 // TODO: victimState, victim animation?
2110 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2111 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2113 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2114 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2117 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2118 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2120 cleanDamage
->damage
+= *blocked_amount
;
2122 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2124 //*hitInfo = 0x00010020;
2125 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2127 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2131 // update at damage Judgement aura duration that applied by attacker at victim
2134 AuraMap
const& vAuras
= pVictim
->GetAuras();
2135 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2137 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2138 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2139 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2141 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2142 (*itr
).second
->SendAuraUpdate(false);
2147 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2149 // victim's damage shield
2150 // yet another hack to fix crashes related to the aura getting removed during iteration
2151 std::set
<Aura
*> alreadyDone
;
2152 uint32 removedAuras
= pVictim
->m_removedAuras
;
2153 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2154 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2157 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2159 alreadyDone
.insert(*i
);
2160 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2161 if (pVictim
->m_removedAuras
> removedAuras
)
2163 removedAuras
= pVictim
->m_removedAuras
;
2164 next
= vDamageShields
.begin();
2170 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2172 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2175 if (!pVictim
->isAlive())
2178 if(IsNonMeleeSpellCasted(false))
2182 if (attType
== BASE_ATTACK
)
2183 hitInfo
= HITINFO_NORMALSWING2
;
2184 else if (attType
== OFF_ATTACK
)
2185 hitInfo
= HITINFO_LEFTSWING
;
2187 return; // ignore ranaged case
2189 uint32 extraAttacks
= m_extraAttacks
;
2191 // melee attack spell casted at main hand attack only
2192 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2194 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2196 // not recent extra attack only at any non extra attack (melee spell case)
2197 if(!extra
&& extraAttacks
)
2199 while(m_extraAttacks
)
2201 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2202 if(m_extraAttacks
> 0)
2210 VictimState victimState
= VICTIMSTATE_NORMAL
;
2212 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2213 uint32 blocked_dmg
= 0;
2214 uint32 absorbed_dmg
= 0;
2215 uint32 resisted_dmg
= 0;
2217 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2219 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2221 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2223 // not recent extra attack only at any non extra attack (miss case)
2224 if(!extra
&& extraAttacks
)
2226 while(m_extraAttacks
)
2228 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2229 if(m_extraAttacks
> 0)
2237 uint32 damage
= CalculateDamage (attType
, false);
2239 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2241 if (hitInfo
& HITINFO_MISS
)
2243 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2247 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2249 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2250 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2254 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2256 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2258 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2259 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2263 if (GetTypeId() == TYPEID_PLAYER
)
2264 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2265 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2267 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2268 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2270 // extra attack only at any non extra attack (normal case)
2271 if(!extra
&& extraAttacks
)
2273 while(m_extraAttacks
)
2275 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2276 if(m_extraAttacks
> 0)
2282 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2284 // Miss chance based on melee
2285 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2287 // Critical hit chance
2288 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2289 // this is to avoid compiler issue when declaring variables inside if
2290 float block_chance
, parry_chance
, dodge_chance
;
2292 // cannot be dodged/parried/blocked
2293 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2295 block_chance
= 0.0f
;
2296 parry_chance
= 0.0f
;
2297 dodge_chance
= 0.0f
;
2301 // parry can be avoided only by some abilites
2302 parry_chance
= pVictim
->GetUnitParryChance();
2303 // block might be bypassed by it as well
2304 block_chance
= pVictim
->GetUnitBlockChance();
2305 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2306 dodge_chance
= pVictim
->GetUnitDodgeChance();
2309 // Only players can have Talent&Spell bonuses
2310 if (GetTypeId() == TYPEID_PLAYER
)
2312 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2313 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2315 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents fpr speed
2317 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2318 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2320 // can't be dodged rogue finishing move
2321 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2323 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2325 dodge_chance
= 0.0f
;
2334 if(Player
* modOwner
= GetSpellModOwner())
2335 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2337 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2339 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);
2342 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2344 // This is only wrapper
2346 // Miss chance based on melee
2347 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2349 // Critical hit chance
2350 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2352 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2353 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2354 float block_chance
= pVictim
->GetUnitBlockChance();
2355 float parry_chance
= pVictim
->GetUnitParryChance();
2357 // Useful if want to specify crit & miss chances for melee, else it could be removed
2358 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2360 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);
2363 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
2365 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2366 return MELEE_HIT_EVADE
;
2368 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2369 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2371 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2372 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2374 // bonus from skills is 0.04%
2375 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2376 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2377 int32 sum
= 0, tmp
= 0;
2378 int32 roll
= urand (0, 10000);
2380 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2381 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2382 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2386 if (tmp
> 0 && roll
< (sum
+= tmp
))
2388 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2389 return MELEE_HIT_MISS
;
2392 // always crit against a sitting target (except 0 crit chance)
2393 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2395 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2396 return MELEE_HIT_CRIT
;
2401 // only players can't dodge if attacker is behind
2402 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2404 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2408 // Reduce dodge chance by attacker expertise rating
2409 if (GetTypeId() == TYPEID_PLAYER
)
2410 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2412 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2413 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2416 if ( (tmp
> 0) // check if unit _can_ dodge
2417 && ((tmp
-= skillBonus
) > 0)
2418 && roll
< (sum
+= tmp
))
2420 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2421 return MELEE_HIT_DODGE
;
2425 // parry & block chances
2427 // check if attack comes from behind, nobody can parry or block if attacker is behind
2428 if (!pVictim
->HasInArc(M_PI
,this))
2430 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2434 // Reduce parry chance by attacker expertise rating
2435 if (GetTypeId() == TYPEID_PLAYER
)
2436 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2438 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2440 int32 tmp
= int32(parry_chance
);
2441 if ( (tmp
> 0) // check if unit _can_ parry
2442 && ((tmp
-= skillBonus
) > 0)
2443 && (roll
< (sum
+= tmp
)))
2445 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2446 return MELEE_HIT_PARRY
;
2450 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2453 if ( (tmp
> 0) // check if unit _can_ block
2454 && ((tmp
-= skillBonus
) > 0)
2455 && (roll
< (sum
+= tmp
)))
2458 tmp
= crit_chance
+ skillBonus2
;
2459 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2461 if ( roll_chance_i(tmp
/100))
2463 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2464 return MELEE_HIT_BLOCK_CRIT
;
2467 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2468 return MELEE_HIT_BLOCK
;
2474 tmp
= crit_chance
+ skillBonus2
;
2476 if (tmp
> 0 && roll
< (sum
+= tmp
))
2478 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2479 return MELEE_HIT_CRIT
;
2482 // 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)
2483 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2484 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2485 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2486 getLevel() < pVictim
->getLevelForTarget(this) )
2488 // cap possible value (with bonuses > max skill)
2489 int32 skill
= attackerWeaponSkill
;
2490 int32 maxskill
= attackerMaxSkillValueForLevel
;
2491 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2493 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2494 tmp
= tmp
> 4000 ? 4000 : tmp
;
2495 if (roll
< (sum
+= tmp
))
2497 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2498 return MELEE_HIT_GLANCING
;
2502 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2504 // mobs can score crushing blows if they're 3 or more levels above victim
2505 // or when their weapon skill is 15 or more above victim's defense skill
2506 tmp
= victimDefenseSkill
;
2507 int32 tmpmax
= victimMaxSkillValueForLevel
;
2508 // having defense above your maximum (from items, talents etc.) has no effect
2509 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2510 // tmp = mob's level * 5 - player's current defense skill
2511 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2514 // add 2% chance per lacking skill point, min. is 15%
2515 tmp
= tmp
* 200 - 1500;
2516 if (roll
< (sum
+= tmp
))
2518 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2519 return MELEE_HIT_CRUSHING
;
2524 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2525 return MELEE_HIT_NORMAL
;
2528 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2530 float min_damage
, max_damage
;
2532 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2533 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2539 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2540 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2543 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2544 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2547 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2548 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2550 // Just for good manner
2558 if (min_damage
> max_damage
)
2560 std::swap(min_damage
,max_damage
);
2563 if(max_damage
== 0.0f
)
2566 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2569 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2571 if(spellProto
->spellLevel
<= 0)
2574 float LvlPenalty
= 0.0f
;
2576 if(spellProto
->spellLevel
< 20)
2577 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2578 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2579 if(LvlFactor
> 1.0f
)
2582 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2585 void Unit::SendAttackStart(Unit
* pVictim
)
2587 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2588 data
<< uint64(GetGUID());
2589 data
<< uint64(pVictim
->GetGUID());
2591 SendMessageToSet(&data
, true);
2592 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2595 void Unit::SendAttackStop(Unit
* victim
)
2600 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2601 data
.append(GetPackGUID());
2602 data
.append(victim
->GetPackGUID()); // can be 0x00...
2603 data
<< uint32(0); // can be 0x1
2604 SendMessageToSet(&data
, true);
2605 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2607 /*if(victim->GetTypeId() == TYPEID_UNIT)
2608 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2612 // Melee based spells can be miss, parry or dodge on this step
2613 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2614 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2616 // Calculate hit chance (more correct for chance mod)
2619 // PvP - PvE melee chances
2620 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2621 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2623 HitChance = 95 - leveldif;
2625 HitChance = 93 - (leveldif - 2) * lchance;
2627 // Hit chance depends from victim auras
2628 if(attType == RANGED_ATTACK)
2629 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2631 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2633 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2634 if(Player *modOwner = GetSpellModOwner())
2635 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2638 float miss_chance= 100.0f - HitChance;
2640 // Bonuses from attacker aura and ratings
2641 if (attType == RANGED_ATTACK)
2642 miss_chance -= m_modRangedHitChance;
2644 miss_chance -= m_modMeleeHitChance;
2646 // bonus from skills is 0.04%
2647 miss_chance -= skillDiff * 0.04f;
2649 // Limit miss chance from 0 to 60%
2650 if (miss_chance < 0.0f)
2652 if (miss_chance > 60.0f)
2657 // Melee based spells hit result calculations
2658 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2660 WeaponAttackType attType = BASE_ATTACK;
2662 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2663 attType = RANGED_ATTACK;
2665 // bonus from skills is 0.04% per skill Diff
2666 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2667 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2668 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2670 uint32 roll = urand (0, 10000);
2671 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2674 uint32 tmp = missChance;
2676 return SPELL_MISS_MISS;
2678 // Same spells cannot be parry/dodge
2679 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2680 return SPELL_MISS_NONE;
2682 // Ranged attack can`t miss too
2683 if (attType == RANGED_ATTACK)
2684 return SPELL_MISS_NONE;
2686 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2689 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2690 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2691 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2693 // Reduce dodge chance by attacker expertise rating
2694 if (GetTypeId() == TYPEID_PLAYER)
2695 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2696 if (dodgeChance < 0)
2699 // Can`t dodge from behind in PvP (but its possible in PvE)
2700 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2703 // Rogue talent`s cant be dodged
2704 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2705 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2707 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2709 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2719 return SPELL_MISS_DODGE;
2722 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2723 // Reduce parry chance by attacker expertise rating
2724 if (GetTypeId() == TYPEID_PLAYER)
2725 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2726 // Can`t parry from behind
2727 if (parryChance < 0 || attackFromBehind)
2732 return SPELL_MISS_PARRY;
2734 return SPELL_MISS_NONE;
2737 // TODO need use unit spell resistances in calculations
2738 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2740 // Can`t miss on dead target (on skinning for example)
2741 if (!pVictim
->isAlive())
2742 return SPELL_MISS_NONE
;
2744 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2745 // PvP - PvE spell misschances per leveldif > 2
2746 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2747 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2749 // Base hit chance from attacker and victim levels
2752 modHitChance
= 96 - leveldif
;
2754 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2756 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2757 if(Player
*modOwner
= GetSpellModOwner())
2758 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2759 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2760 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2761 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2762 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2763 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2764 if (IsAreaOfEffectSpell(spell
))
2765 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2766 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2767 if (IsDispelSpell(spell
))
2768 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2769 // Chance resist mechanic (select max value from every mechanic spell effect)
2770 int32 resist_mech
= 0;
2771 // Get effects mechanic and chance
2772 for(int eff
= 0; eff
< 3; ++eff
)
2774 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2777 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2778 if (resist_mech
< temp
)
2783 modHitChance
-=resist_mech
;
2785 // Chance resist debuff
2786 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2788 int32 HitChance
= modHitChance
* 100;
2789 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2790 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2792 // Decrease hit chance from victim rating bonus
2793 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2794 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2796 if (HitChance
< 100) HitChance
= 100;
2797 if (HitChance
> 9900) HitChance
= 9900;
2799 uint32 rand
= urand(0,10000);
2800 if (rand
> HitChance
)
2801 return SPELL_MISS_RESIST
;
2802 return SPELL_MISS_NONE
;
2805 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2807 // Return evade for units in evade mode
2808 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2809 return SPELL_MISS_EVADE
;
2811 // Check for immune (use charges)
2812 if (pVictim
->IsImmunedToSpell(spell
,true))
2813 return SPELL_MISS_IMMUNE
;
2815 // All positive spells can`t miss
2816 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2817 if (IsPositiveSpell(spell
->Id
))
2818 return SPELL_MISS_NONE
;
2820 // Check for immune (use charges)
2821 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2822 return SPELL_MISS_IMMUNE
;
2824 // Try victim reflect spell
2827 // specialized first
2828 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2829 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2831 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2833 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2834 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2836 if((*i
)->m_procCharges
> 0)
2838 --(*i
)->m_procCharges
;
2839 if((*i
)->m_procCharges
==0)
2840 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2842 return SPELL_MISS_REFLECT
;
2847 // generic reflection
2848 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2849 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2851 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2852 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2854 if((*i
)->m_procCharges
> 0)
2856 --(*i
)->m_procCharges
;
2857 if((*i
)->m_procCharges
==0)
2858 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2860 return SPELL_MISS_REFLECT
;
2865 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2866 for (int i
=0;i
<3;i
++)
2868 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2869 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2870 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2871 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2872 return SPELL_MISS_NONE
;
2875 // TODO need use this code for spell hit result calculation
2876 // now code commented for compotability
2877 switch (spell
->DmgClass
)
2879 case SPELL_DAMAGE_CLASS_RANGED
:
2880 case SPELL_DAMAGE_CLASS_MELEE
:
2881 // return MeleeSpellHitResult(pVictim, spell);
2882 return SPELL_MISS_NONE
;
2883 case SPELL_DAMAGE_CLASS_NONE
:
2884 case SPELL_DAMAGE_CLASS_MAGIC
:
2885 return MagicSpellHitResult(pVictim
, spell
);
2887 return SPELL_MISS_NONE
;
2890 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2895 // Base misschance 5%
2896 float misschance
= 5.0f
;
2898 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2899 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2901 bool isNormal
= false;
2902 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2904 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2910 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2920 // PvP : PvE melee misschances per leveldif > 2
2921 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2923 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2927 // Hit chance from attacker based on ratings and auras
2928 float m_modHitChance
;
2929 if (attType
== RANGED_ATTACK
)
2930 m_modHitChance
= m_modRangedHitChance
;
2932 m_modHitChance
= m_modMeleeHitChance
;
2935 misschance
+= (leveldif
- m_modHitChance
);
2937 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2939 // Hit chance for victim based on ratings
2940 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2942 if (attType
== RANGED_ATTACK
)
2943 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2945 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2948 // Modify miss chance by victim auras
2949 if(attType
== RANGED_ATTACK
)
2950 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2952 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2954 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2955 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2956 misschance
-= skillBonus
* 0.04f
;
2958 // Limit miss chance from 0 to 60%
2959 if ( misschance
< 0.0f
)
2961 if ( misschance
> 60.0f
)
2967 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2969 if(GetTypeId() == TYPEID_PLAYER
)
2971 // in PvP use full skill instead current skill value
2972 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2973 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2974 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2975 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2979 return GetUnitMeleeSkill(target
);
2982 float Unit::GetUnitDodgeChance() const
2984 if(hasUnitState(UNIT_STAT_STUNNED
))
2986 if( GetTypeId() == TYPEID_PLAYER
)
2987 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2990 if(((Creature
const*)this)->isTotem())
2995 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2996 return dodge
> 0.0f
? dodge
: 0.0f
;
3001 float Unit::GetUnitParryChance() const
3003 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3006 float chance
= 0.0f
;
3008 if(GetTypeId() == TYPEID_PLAYER
)
3010 Player
const* player
= (Player
const*)this;
3011 if(player
->CanParry() )
3013 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3015 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3018 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3021 else if(GetTypeId() == TYPEID_UNIT
)
3023 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3026 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3030 return chance
> 0.0f
? chance
: 0.0f
;
3033 float Unit::GetUnitBlockChance() const
3035 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3038 if(GetTypeId() == TYPEID_PLAYER
)
3040 Player
const* player
= (Player
const*)this;
3041 if(player
->CanBlock() )
3043 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3044 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3045 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3047 // is player but has no block ability or no not broken shield equiped
3052 if(((Creature
const*)this)->isTotem())
3057 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3058 return block
> 0.0f
? block
: 0.0f
;
3063 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3067 if(GetTypeId() == TYPEID_PLAYER
)
3072 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3075 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3078 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3080 // Just for good manner
3089 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3093 if(attackType
== RANGED_ATTACK
)
3094 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3096 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3098 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3100 // reduce crit chance from Rating for players
3101 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3103 if (attackType
==RANGED_ATTACK
)
3104 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3106 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3114 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3117 if(GetTypeId() == TYPEID_PLAYER
)
3119 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3121 // feral or unarmed skill only for base attack
3122 if(attType
!= BASE_ATTACK
&& !item
)
3125 if(((Player
*)this)->IsInFeralForm())
3126 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3128 // weaon skill or (unarmed for base attack)
3129 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3131 // in PvP use full skill instead current skill value
3132 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3133 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3134 : ((Player
*)this)->GetSkillValue(skill
);
3135 // Modify value from ratings
3136 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3139 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3140 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3141 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3145 value
= GetUnitMeleeSkill(target
);
3149 void Unit::_UpdateSpells( uint32 time
)
3151 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3152 _UpdateAutoRepeatSpell();
3154 // remove finished spells from current pointers
3155 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3157 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3159 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3160 m_currentSpells
[i
] = NULL
; // remove pointer
3164 // TODO: Find a better way to prevent crash when multiple auras are removed.
3166 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3168 (*i
).second
->SetUpdated(false);
3170 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3176 // prevent double update
3177 if ((*i
).second
->IsUpdated())
3179 (*i
).second
->SetUpdated(true);
3180 (*i
).second
->Update( time
);
3181 // several auras can be deleted due to update
3184 if (m_Auras
.empty()) break;
3185 next
= m_Auras
.begin();
3191 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3195 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3210 if(!m_gameObj
.empty())
3212 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3213 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3216 //(*i)->Update( difftime );
3217 if( !(*ite1
)->isSpawned() )
3219 (*ite1
)->SetOwnerGUID(0);
3220 (*ite1
)->SetRespawnTime(0);
3222 dnext1
= m_gameObj
.erase(ite1
);
3230 void Unit::_UpdateAutoRepeatSpell()
3232 //check "realtime" interrupts
3233 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3235 // cancel wand shoot
3236 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3237 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3238 m_AutoRepeatFirstCast
= true;
3243 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3244 setAttackTimer(RANGED_ATTACK
,500);
3245 m_AutoRepeatFirstCast
= false;
3248 if (isAttackReady(RANGED_ATTACK
))
3250 // Check if able to cast
3251 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3253 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3258 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3259 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3261 // all went good, reset attack
3262 resetAttackTimer(RANGED_ATTACK
);
3266 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3268 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3270 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3272 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3274 // break same type spell if it is not delayed
3275 InterruptSpell(CSpellType
,false);
3277 // special breakage effects:
3280 case CURRENT_GENERIC_SPELL
:
3282 // generic spells always break channeled not delayed spells
3283 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3285 // autorepeat breaking
3286 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3288 // break autorepeat if not Auto Shot
3289 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3290 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3291 m_AutoRepeatFirstCast
= true;
3295 case CURRENT_CHANNELED_SPELL
:
3297 // channel spells always break generic non-delayed and any channeled spells
3298 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3299 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3301 // it also does break autorepeat if not Auto Shot
3302 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3303 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3304 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3307 case CURRENT_AUTOREPEAT_SPELL
:
3309 // only Auto Shoot does not break anything
3310 if (pSpell
->m_spellInfo
->Category
== 351)
3312 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3313 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3314 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3316 // special action: set first cast flag
3317 m_AutoRepeatFirstCast
= true;
3322 // other spell types don't break anything now
3326 // current spell (if it is still here) may be safely deleted now
3327 if (m_currentSpells
[CSpellType
])
3328 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3330 // set new current spell
3331 m_currentSpells
[CSpellType
] = pSpell
;
3332 pSpell
->SetReferencedFromCurrent(true);
3335 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3337 assert(spellType
< CURRENT_MAX_SPELL
);
3339 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3341 // send autorepeat cancel message for autorepeat spells
3342 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3344 if(GetTypeId()==TYPEID_PLAYER
)
3345 ((Player
*)this)->SendAutoRepeatCancel();
3348 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3349 m_currentSpells
[spellType
]->cancel();
3350 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3351 m_currentSpells
[spellType
] = NULL
;
3355 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3357 // We don't do loop here to explicitly show that melee spell is excluded.
3358 // Maybe later some special spells will be excluded too.
3360 // generic spells are casted when they are not finished and not delayed
3361 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3362 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3363 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3366 // channeled spells may be delayed, but they are still considered casted
3367 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3368 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3371 // autorepeat spells may be finished or delayed, but they are still considered casted
3372 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3378 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3380 // generic spells are interrupted if they are not finished or delayed
3381 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3383 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3384 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3385 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3386 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3387 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3390 // autorepeat spells are interrupted if they are not finished or delayed
3391 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3393 // send disable autorepeat packet in any case
3394 if(GetTypeId()==TYPEID_PLAYER
)
3395 ((Player
*)this)->SendAutoRepeatCancel();
3397 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3398 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3399 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3400 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3401 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3404 // channeled spells are interrupted if they are not finished, even if they are delayed
3405 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3407 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3408 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3409 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3410 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3414 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3416 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3417 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3418 return m_currentSpells
[i
];
3422 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3424 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3427 void Unit::SetInFront(Unit
const* target
)
3429 SetOrientation(GetAngle(target
));
3432 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3434 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3437 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3440 return c
->canSwim();
3442 return c
->canWalk() || c
->canFly();
3445 bool Unit::IsInWater() const
3447 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3450 bool Unit::IsUnderWater() const
3452 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3455 void Unit::DeMorph()
3457 SetDisplayId(GetNativeDisplayId());
3460 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3464 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3465 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3466 modifier
+= (*i
)->GetModifier()->m_amount
;
3471 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3473 float multipler
= 1.0f
;
3475 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3476 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3477 multipler
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3482 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3486 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3487 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3488 if ((*i
)->GetModifier()->m_amount
> modifier
)
3489 modifier
= (*i
)->GetModifier()->m_amount
;
3494 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3498 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3499 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3500 if ((*i
)->GetModifier()->m_amount
< modifier
)
3501 modifier
= (*i
)->GetModifier()->m_amount
;
3506 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3510 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3511 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3513 Modifier
* mod
= (*i
)->GetModifier();
3514 if (mod
->m_miscvalue
& misc_mask
)
3515 modifier
+= mod
->m_amount
;
3520 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3522 float multipler
= 1.0f
;
3524 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3525 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3527 Modifier
* mod
= (*i
)->GetModifier();
3528 if (mod
->m_miscvalue
& misc_mask
)
3529 multipler
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3534 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3538 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3539 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3541 Modifier
* mod
= (*i
)->GetModifier();
3542 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3543 modifier
= mod
->m_amount
;
3549 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3553 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3554 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3556 Modifier
* mod
= (*i
)->GetModifier();
3557 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3558 modifier
= mod
->m_amount
;
3564 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3568 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3569 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3571 Modifier
* mod
= (*i
)->GetModifier();
3572 if (mod
->m_miscvalue
== misc_value
)
3573 modifier
+= mod
->m_amount
;
3578 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3580 float multipler
= 1.0f
;
3582 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3583 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3585 Modifier
* mod
= (*i
)->GetModifier();
3586 if (mod
->m_miscvalue
== misc_value
)
3587 multipler
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3592 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3596 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3597 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3599 Modifier
* mod
= (*i
)->GetModifier();
3600 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3601 modifier
= mod
->m_amount
;
3607 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3611 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3612 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3614 Modifier
* mod
= (*i
)->GetModifier();
3615 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3616 modifier
= mod
->m_amount
;
3622 bool Unit::AddAura(Aura
*Aur
)
3624 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3625 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3626 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3632 if(Aur
->GetTarget() != this)
3634 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3635 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3636 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3641 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3643 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3644 AuraMap::iterator i
= m_Auras
.find( spair
);
3646 // take out same spell
3647 if (i
!= m_Auras
.end())
3649 // passive and persistent auras can stack with themselves any number of times
3650 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3652 // replace aura if next will > spell StackAmount
3653 if(aurSpellInfo
->StackAmount
)
3655 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3656 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3658 // if StackAmount==0 not allow auras from same caster
3661 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3663 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3665 // can be only single (this check done at _each_ aura add
3666 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3671 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3674 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3675 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3676 case SPELL_AURA_PERIODIC_LEECH
:
3677 case SPELL_AURA_PERIODIC_HEAL
:
3678 case SPELL_AURA_OBS_MOD_HEALTH
:
3679 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3680 case SPELL_AURA_PERIODIC_ENERGIZE
:
3681 case SPELL_AURA_OBS_MOD_MANA
:
3682 case SPELL_AURA_POWER_BURN_MANA
:
3684 default: // not allow
3685 // can be only single (this check done at _each_ aura add
3686 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3698 // passive auras stack with all (except passive spell proc auras)
3699 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3700 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3702 if (!RemoveNoStackAurasDueToAura(Aur
))
3705 return false; // couldnt remove conflicting aura with higher rank
3709 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3710 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3712 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3715 Unit
* caster
= Aur
->GetCaster();
3716 if(!caster
) // caster deleted and not required adding scAura
3719 bool restart
= false;
3720 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3721 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3723 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3724 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3726 if ((*itr
)->IsInUse())
3728 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());
3731 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3740 scAuras
.push_back(Aur
);
3746 // add aura, register in lists and arrays
3748 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3749 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3751 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3754 Aur
->ApplyModifier(true,true);
3755 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3759 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3761 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3764 AuraMap::iterator i
,next
;
3765 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3769 uint32 i_spellId
= (*i
).second
->GetId();
3770 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3772 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3774 RemoveAurasDueToSpell(i_spellId
);
3776 if( m_Auras
.empty() )
3779 next
= m_Auras
.begin();
3785 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3790 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3794 uint32 spellId
= Aur
->GetId();
3795 uint32 effIndex
= Aur
->GetEffIndex();
3797 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3799 AuraMap::iterator i
,next
;
3800 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3804 if (!(*i
).second
) continue;
3806 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3811 uint32 i_spellId
= i_spellProto
->Id
;
3813 if(IsPassiveSpell(i_spellId
))
3815 if(IsPassiveStackableSpell(i_spellId
))
3818 // passive non-stackable spells not stackable only with another rank of same spell
3819 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3823 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3825 if(i_spellId
== spellId
) continue;
3827 bool is_triggered_by_spell
= false;
3828 // prevent triggered aura of removing aura that triggered it
3829 for(int j
= 0; j
< 3; ++j
)
3830 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3831 is_triggered_by_spell
= true;
3832 if (is_triggered_by_spell
) continue;
3834 for(int j
= 0; j
< 3; ++j
)
3836 // prevent remove dummy triggered spells at next effect aura add
3837 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggred spell
3839 case SPELL_EFFECT_DUMMY
:
3842 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3847 if(is_triggered_by_spell
)
3850 // prevent remove form main spell by triggered passive spells
3851 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3853 case SPELL_AURA_MOD_SHAPESHIFT
:
3856 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3857 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3858 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3864 if(!is_triggered_by_spell
)
3866 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3868 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3870 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3872 // cannot remove higher rank
3873 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3874 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3877 // Its a parent aura (create this aura in ApplyModifier)
3878 if ((*i
).second
->IsInUse())
3880 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());
3883 RemoveAurasDueToSpell(i_spellId
);
3885 if( m_Auras
.empty() )
3888 next
= m_Auras
.begin();
3890 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3892 // Its a parent aura (create this aura in ApplyModifier)
3893 if ((*i
).second
->IsInUse())
3895 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());
3898 RemoveAurasDueToSpell(i_spellId
);
3900 if( m_Auras
.empty() )
3903 next
= m_Auras
.begin();
3905 // Potions stack aura by aura (elixirs/flask already checked)
3906 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3908 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3910 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3911 return false; // cannot remove higher rank
3913 // Its a parent aura (create this aura in ApplyModifier)
3914 if ((*i
).second
->IsInUse())
3916 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());
3928 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3930 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3931 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3933 if(iter
->second
!=except
)
3936 iter
= m_Auras
.lower_bound(spair
);
3943 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3945 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3947 Aura
*aur
= iter
->second
;
3948 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3950 // Custom dispel case
3951 // Unstable Affliction
3952 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3954 int32 damage
= aur
->GetModifier()->m_amount
*9;
3955 uint64 caster_guid
= aur
->GetCasterGUID();
3958 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3960 // backfire damage and silence
3961 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3963 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3966 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3973 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3975 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3977 Aura
*aur
= iter
->second
;
3978 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3980 int32 basePoints
= aur
->GetBasePoints();
3981 // construct the new aura for the attacker
3982 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3986 // set its duration and maximum duration
3987 // max duration 2 minutes (in msecs)
3988 int32 dur
= aur
->GetAuraDuration();
3989 const int32 max_dur
= 2*MINUTE
*1000;
3990 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3991 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3993 // add the new aura to stealer
3994 stealer
->AddAura(new_aur
);
3996 // Remove aura as dispel
3997 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
4004 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4006 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4008 if (iter
->second
->GetId() == spellId
)
4009 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4015 void Unit::RemoveAurasWithDispelType( DispelType type
)
4017 // Create dispel mask by dispel type
4018 uint32 dispelMask
= GetDispellMask(type
);
4019 // Dispel all existing auras vs current dispell type
4020 AuraMap
& auras
= GetAuras();
4021 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4023 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4024 if( (1<<spell
->Dispel
) & dispelMask
)
4027 RemoveAurasDueToSpell(spell
->Id
);
4028 itr
= auras
.begin();
4035 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4037 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4038 if(iter
!= m_Auras
.end())
4042 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4044 for (int i
= 0; i
< 3; ++i
)
4045 RemoveAura(spellId
,i
,except
);
4048 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4050 for (int k
=0; k
< 3; ++k
)
4052 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4053 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4055 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4058 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4066 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4068 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4070 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4077 void Unit::RemoveNotOwnSingleTargetAuras()
4079 // single target auras from other casters
4080 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4082 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4088 // single target auras at other targets
4089 AuraList
& scAuras
= GetSingleCastAuras();
4090 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4093 if (aura
->GetTarget()!=this)
4095 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4096 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4097 iter
= scAuras
.begin();
4105 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4107 if (IsSingleTargetSpell((*i
).second
->GetSpellProto()))
4109 if(Unit
* caster
= (*i
).second
->GetCaster())
4111 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4112 scAuras
.remove((*i
).second
);
4116 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4121 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4123 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
4126 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4127 Aura
* Aur
= i
->second
;
4129 Aur
->SetRemoveMode(mode
);
4130 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4131 // remove aura from list before to prevent deleting it before
4133 ++m_removedAuras
; // internal count used by unit update
4135 // Status unsummoned at aura remove
4136 Totem
* statue
= NULL
;
4137 if(IsChanneledSpell(Aur
->GetSpellProto()))
4138 if(Unit
* caster
= Aur
->GetCaster())
4139 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4140 statue
= ((Totem
*)caster
);
4142 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4143 Aur
->ApplyModifier(false,true);
4150 // only way correctly remove all auras from list
4151 if( m_Auras
.empty() )
4154 i
= m_Auras
.begin();
4157 void Unit::RemoveAllAuras()
4159 while (!m_Auras
.empty())
4161 AuraMap::iterator iter
= m_Auras
.begin();
4166 void Unit::RemoveAllAurasOnDeath()
4168 // used just after dieing to remove all visible auras
4169 // and disable the mods for the passive ones
4170 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4172 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4173 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4179 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4181 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4182 if (iter
!= m_Auras
.end())
4184 if (iter
->second
->GetAuraDuration() < delaytime
)
4185 iter
->second
->SetAuraDuration(0);
4187 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4188 iter
->second
->SendAuraUpdate(false);
4189 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4193 void Unit::_RemoveAllAuraMods()
4195 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4197 (*i
).second
->ApplyModifier(false);
4201 void Unit::_ApplyAllAuraMods()
4203 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4205 (*i
).second
->ApplyModifier(true);
4209 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4211 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4212 if (iter
!= m_Auras
.end())
4213 return iter
->second
;
4217 void Unit::AddDynObject(DynamicObject
* dynObj
)
4219 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4222 void Unit::RemoveDynObject(uint32 spellid
)
4224 if(m_dynObjGUIDs
.empty())
4226 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4228 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4231 i
= m_dynObjGUIDs
.erase(i
);
4233 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4236 i
= m_dynObjGUIDs
.erase(i
);
4243 void Unit::RemoveAllDynObjects()
4245 while(!m_dynObjGUIDs
.empty())
4247 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4250 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4254 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4256 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4258 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4261 i
= m_dynObjGUIDs
.erase(i
);
4265 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4272 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4274 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4276 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4279 i
= m_dynObjGUIDs
.erase(i
);
4283 if (dynObj
->GetSpellId() == spellId
)
4290 void Unit::AddGameObject(GameObject
* gameObj
)
4292 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4293 m_gameObj
.push_back(gameObj
);
4294 gameObj
->SetOwnerGUID(GetGUID());
4297 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4299 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4301 // GO created by some spell
4302 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4304 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4305 // Need activate spell use for owner
4306 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4307 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4309 gameObj
->SetOwnerGUID(0);
4310 m_gameObj
.remove(gameObj
);
4313 gameObj
->SetRespawnTime(0);
4318 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4320 if(m_gameObj
.empty())
4322 std::list
<GameObject
*>::iterator i
, next
;
4323 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4326 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4328 (*i
)->SetOwnerGUID(0);
4331 (*i
)->SetRespawnTime(0);
4335 next
= m_gameObj
.erase(i
);
4342 void Unit::RemoveAllGameObjects()
4344 // remove references to unit
4345 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4347 (*i
)->SetOwnerGUID(0);
4348 (*i
)->SetRespawnTime(0);
4350 i
= m_gameObj
.erase(i
);
4354 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4356 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4357 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4358 data
.append(target
->GetPackGUID());
4359 data
.append(GetPackGUID());
4360 data
<< uint32(SpellID
);
4361 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4362 data
<< uint32(0); // wotlk
4363 data
<< uint8(damageSchoolMask
); // spell school
4364 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4365 data
<< uint32(Resist
); // resist
4366 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
4367 data
<< uint8(0); // unk isFromAura
4368 data
<< uint32(Blocked
); // blocked
4369 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4370 data
<< uint8(0); // isDebug?
4371 SendMessageToSet( &data
, true );
4374 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4376 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4377 data
<< uint32(spellID
);
4378 data
<< uint64(GetGUID());
4379 data
<< uint8(0); // can be 0 or 1
4380 data
<< uint32(1); // target count
4381 // for(i = 0; i < target count; ++i)
4382 data
<< uint64(target
->GetGUID()); // target GUID
4383 data
<< uint8(missInfo
);
4385 SendMessageToSet(&data
, true);
4388 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4390 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4392 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4393 data
<< uint32(HitInfo
); // flags
4394 data
.append(GetPackGUID());
4395 data
.append(target
->GetPackGUID());
4396 data
<< uint32(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);// damage
4397 data
<< uint32(0); // overkill value
4399 data
<< (uint8
)SwingType
; // count?
4401 // for(i = 0; i < SwingType; ++i)
4402 data
<< (uint32
)damageSchoolMask
;
4403 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4404 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4407 if(HitInfo
& (HITINFO_ABSORB
| HITINFO_ABSORB2
))
4409 // for(i = 0; i < SwingType; ++i)
4410 data
<< uint32(AbsorbDamage
);
4414 if(HitInfo
& (HITINFO_RESIST
| HITINFO_RESIST2
))
4416 // for(i = 0; i < SwingType; ++i)
4417 data
<< uint32(Resist
);
4421 data
<< (uint8
)TargetState
;
4425 if(HitInfo
& HITINFO_BLOCK
)
4427 data
<< uint32(BlockedAmount
);
4430 if(HitInfo
& HITINFO_UNK3
)
4435 if(HitInfo
& HITINFO_UNK1
)
4446 for(uint8 i
= 0; i
< 5; ++i
)
4454 SendMessageToSet( &data
, true );
4457 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4459 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4461 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4463 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4464 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
4465 // That is the question though if it's fully correct
4466 if(procSpell
&& !isTriggeredSpell
)
4468 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4470 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4471 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4472 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4473 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4474 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4476 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4478 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4479 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4480 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4481 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4482 attType
= RANGED_ATTACK
;
4485 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4486 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4488 // Not much to do if no flags are set.
4491 // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4492 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4493 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4496 // Now go on with a victim's events'n'auras
4497 // Not much to do if no flags are set or there is no victim
4498 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4500 // procces auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4501 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4502 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4506 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4511 uint32 procAttacker
= PROC_FLAG_NONE
;
4512 uint32 procVictim
= PROC_FLAG_NONE
;
4516 case MELEE_HIT_EVADE
:
4518 case MELEE_HIT_MISS
:
4519 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4521 procAttacker
= PROC_FLAG_MISS
;
4524 case MELEE_HIT_BLOCK_CRIT
:
4525 case MELEE_HIT_CRIT
:
4526 if(spellCasted
&& attType
== BASE_ATTACK
)
4528 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4529 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4530 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4532 procVictim
|= PROC_FLAG_BLOCK
;
4533 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4536 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4538 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4539 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4543 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4544 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4547 case MELEE_HIT_PARRY
:
4548 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4549 procVictim
= PROC_FLAG_PARRY
;
4551 case MELEE_HIT_BLOCK
:
4552 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4553 procVictim
= PROC_FLAG_BLOCK
;
4555 case MELEE_HIT_DODGE
:
4556 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4557 procVictim
= PROC_FLAG_DODGE
;
4559 case MELEE_HIT_CRUSHING
:
4560 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4562 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4563 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4567 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4568 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4572 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4574 procAttacker
= PROC_FLAG_HIT_MELEE
;
4575 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4579 procAttacker
= PROC_FLAG_HIT_RANGED
;
4580 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4586 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4588 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4589 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4592 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, SpellEntry
const *hasteSpell
, uint32
/*effIndex*/, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32
/*procFlag*/, uint32 cooldown
)
4594 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4595 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4597 uint32 triggered_spell_id
= 0;
4598 Unit
* target
= pVictim
;
4599 int32 basepoints0
= 0;
4601 switch(hasteSpell
->SpellFamilyName
)
4603 case SPELLFAMILY_ROGUE
:
4605 switch(hasteSpell
->Id
)
4611 target
= SelectNearbyTarget();
4614 basepoints0
= damage
;
4615 triggered_spell_id
= 22482;
4623 // processed charge only counting case
4624 if(!triggered_spell_id
)
4627 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4631 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4636 if(!target
|| target
!=this && !target
->isAlive())
4639 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4643 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4645 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4647 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4648 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4653 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, SpellEntry
const *dummySpell
, uint32 effIndex
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4655 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4656 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4658 uint32 triggered_spell_id
= 0;
4659 Unit
* target
= pVictim
;
4660 int32 basepoints0
= 0;
4662 switch(dummySpell
->SpellFamilyName
)
4664 case SPELLFAMILY_GENERIC
:
4666 switch (dummySpell
->Id
)
4672 // prevent damage back from weapon special attacks
4673 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4676 // return damage % to attacker but < 50% own total health
4677 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4678 if(basepoints0
> GetMaxHealth()/2)
4679 basepoints0
= GetMaxHealth()/2;
4681 triggered_spell_id
= 25997;
4689 // prevent chain of triggred spell from same triggred spell
4690 if(procSpell
&& procSpell
->Id
==26654)
4693 target
= SelectNearbyTarget();
4697 triggered_spell_id
= 26654;
4703 if (!procSpell
|| procSpell
->Id
== 24659)
4705 // Need remove one 24659 aura
4706 RemoveSingleAuraFromStack(24659, 0);
4707 RemoveSingleAuraFromStack(24659, 1);
4710 // Restless Strength
4713 // Need remove one 24662 aura
4714 RemoveSingleAuraFromStack(24662, 0);
4717 // Adaptive Warding (Frostfire Regalia set)
4725 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4726 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4728 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4730 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4740 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4742 case SPELL_SCHOOL_NORMAL
:
4743 case SPELL_SCHOOL_HOLY
:
4744 return false; // ignored
4745 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4746 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4747 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4748 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4749 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4757 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4765 for(int j
= 0; j
< 3; ++j
)
4767 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4776 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4778 case SPELL_SCHOOL_NORMAL
:
4779 return false; // ignore
4780 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4781 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4782 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4783 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4784 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4785 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4793 // Mana Leech (Passive) (Priest Pet Aura)
4797 target
= GetOwner();
4801 basepoints0
= int32(damage
* 2.5f
); // manaregen
4802 triggered_spell_id
= 34650;
4808 // Cast finish spell at last charge
4809 if (triggeredByAura
->m_procCharges
> 1)
4813 triggered_spell_id
= 33494;
4816 // Twisted Reflection (boss spell)
4818 triggered_spell_id
= 21064;
4820 // Vampiric Aura (boss spell)
4823 basepoints0
= 3 * damage
; // 300%
4824 if (basepoints0
< 0)
4827 triggered_spell_id
= 31285;
4831 // Aura of Madness (Darkmoon Card: Madness trinket)
4832 //=====================================================
4833 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4834 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4835 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4836 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4837 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4838 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4839 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4840 // 41011 Martyr Complex: +35 stamina (All classes)
4841 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4842 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4845 if(GetTypeId() != TYPEID_PLAYER
)
4848 // Select class defined buff
4851 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4852 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4854 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4855 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4858 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4859 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4861 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4862 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4865 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4866 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4867 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4868 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4870 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4871 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4874 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4876 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4877 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4885 if (roll_chance_i(10))
4886 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4890 // TODO: need find item for aura and triggered spells
4891 // Sunwell Exalted Caster Neck (??? neck)
4892 // cast ??? Light's Wrath if Exalted by Aldor
4893 // cast ??? Arcane Bolt if Exalted by Scryers*/
4895 return false; // disable for while
4898 if(GetTypeId() != TYPEID_PLAYER)
4901 // Get Aldor reputation rank
4902 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4905 triggered_spell_id = ???
4908 // Get Scryers reputation rank
4909 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4911 triggered_spell_id = ???
4916 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4917 // cast 45479 Light's Wrath if Exalted by Aldor
4918 // cast 45429 Arcane Bolt if Exalted by Scryers
4921 if(GetTypeId() != TYPEID_PLAYER
)
4924 // Get Aldor reputation rank
4925 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4928 triggered_spell_id
= 45479;
4931 // Get Scryers reputation rank
4932 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4934 triggered_spell_id
= 45429;
4939 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4940 // cast 45480 Light's Strength if Exalted by Aldor
4941 // cast 45428 Arcane Strike if Exalted by Scryers
4944 if(GetTypeId() != TYPEID_PLAYER
)
4947 // Get Aldor reputation rank
4948 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4951 triggered_spell_id
= 45480;
4954 // Get Scryers reputation rank
4955 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4957 triggered_spell_id
= 45428;
4962 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4963 // cast 45431 Arcane Insight if Exalted by Aldor
4964 // cast 45432 Light's Ward if Exalted by Scryers
4967 if(GetTypeId() != TYPEID_PLAYER
)
4970 // Get Aldor reputation rank
4971 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4974 triggered_spell_id
= 45432;
4977 // Get Scryers reputation rank
4978 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4981 triggered_spell_id
= 45431;
4986 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4987 // cast 45478 Light's Salvation if Exalted by Aldor
4988 // cast 45430 Arcane Surge 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
= 45478;
5001 // Get Scryers reputation rank
5002 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5004 triggered_spell_id
= 45430;
5012 case SPELLFAMILY_MAGE
:
5015 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5017 if (getPowerType() != POWER_MANA
)
5021 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5023 triggered_spell_id
= 29442;
5026 // Master of Elements
5027 if (dummySpell
->SpellIconID
== 1920)
5033 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5034 if( basepoints0
<=0 )
5038 triggered_spell_id
= 29077;
5041 switch(dummySpell
->Id
)
5050 switch (dummySpell
->Id
)
5052 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5053 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5054 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5055 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5056 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5058 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5062 triggered_spell_id
= 12654;
5068 //last charge and crit
5069 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5071 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5072 return true; // charge counting (will removed)
5075 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5076 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5081 case SPELLFAMILY_WARRIOR
:
5084 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5086 // check attack comes not from behind
5087 if (!HasInArc(M_PI
, pVictim
))
5090 triggered_spell_id
= 22858;
5095 case SPELLFAMILY_WARLOCK
:
5097 // Seed of Corruption
5098 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5100 Modifier
* mod
= triggeredByAura
->GetModifier();
5101 // if damage is more than need or target die from damage deal finish spell
5102 // FIX ME: not triggered currently at death
5103 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5105 // remember guid before aura delete
5106 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5108 // Remove aura (before cast for prevent infinite loop handlers)
5109 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5111 // Cast finish spell (triggeredByAura already not exist!)
5112 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5113 return true; // no hidden cooldown
5117 mod
->m_amount
-=damage
;
5120 // Seed of Corruption (Mobs cast) - no die req
5121 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5123 Modifier
* mod
= triggeredByAura
->GetModifier();
5124 // if damage is more than need deal finish spell
5125 if( mod
->m_amount
<= damage
)
5127 // remember guid before aura delete
5128 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5130 // Remove aura (before cast for prevent infinite loop handlers)
5131 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5133 // Cast finish spell (triggeredByAura already not exist!)
5134 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5135 return true; // no hidden cooldown
5138 mod
->m_amount
-=damage
;
5141 switch(dummySpell
->Id
)
5148 triggered_spell_id
= 17941;
5157 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5159 triggered_spell_id
= 30294;
5162 // Shadowflame (Voidheart Raiment set bonus)
5165 triggered_spell_id
= 37379;
5168 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5176 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5177 triggered_spell_id
= 37382;
5180 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5183 triggered_spell_id
= 37378;
5189 case SPELLFAMILY_PRIEST
:
5192 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5194 if(!pVictim
|| !pVictim
->isAlive())
5197 // pVictim is caster of aura
5198 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5202 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5203 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5204 return true; // no hidden cooldown
5206 switch(dummySpell
->Id
)
5211 if(!pVictim
|| !pVictim
->isAlive())
5214 // pVictim is caster of aura
5215 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5219 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5220 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5221 return true; // no hidden cooldown
5223 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5226 // Shadow Word: Pain
5227 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5228 triggered_spell_id
= 40441;
5230 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5231 triggered_spell_id
= 40440;
5238 // Oracle Healing Bonus ("Garments of the Oracle" set)
5242 basepoints0
= int32(damage
* 10/100);
5244 triggered_spell_id
= 26170;
5247 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5250 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5254 basepoints0
= int32(damage
* 2 / 100);
5256 triggered_spell_id
= 39373;
5259 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5262 triggered_spell_id
= 28810;
5268 case SPELLFAMILY_DRUID
:
5270 switch(dummySpell
->Id
)
5272 // Healing Touch (Dreamwalker Raiment set)
5276 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5278 triggered_spell_id
= 28742;
5281 // Healing Touch Refund (Idol of Longevity trinket)
5285 triggered_spell_id
= 28848;
5288 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5293 triggered_spell_id
= 37238;
5296 // Druid Tier 6 Trinket
5302 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5304 triggered_spell_id
= 40445;
5308 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5310 triggered_spell_id
= 40446;
5313 // Mangle (cat/bear)
5314 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5316 triggered_spell_id
= 40452;
5322 if (!roll_chance_f(chance
))
5331 // Deadly Interrupt Effect
5332 triggered_spell_id
= 32747;
5338 case SPELLFAMILY_ROGUE
:
5340 switch(dummySpell
->Id
)
5342 // Deadly Throw Interrupt
5345 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5349 triggered_spell_id
= 32747;
5354 if( dummySpell
->SpellIconID
== 2116 )
5359 // only rogue's finishing moves (maybe need additional checks)
5360 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5361 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5365 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5366 if(basepoints0
<= 0)
5370 triggered_spell_id
= 31663;
5375 case SPELLFAMILY_HUNTER
:
5377 // Thrill of the Hunt
5378 if ( dummySpell
->SpellIconID
== 2236 )
5384 basepoints0
= procSpell
->manaCost
* 40/100;
5385 if(basepoints0
<= 0)
5389 triggered_spell_id
= 34720;
5394 case SPELLFAMILY_PALADIN
:
5396 // Seal of Righteousness - melee proc dummy
5397 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5399 if(GetTypeId() != TYPEID_PLAYER
)
5403 switch (triggeredByAura
->GetId())
5405 case 21084: spellId
= 25742; break; // Rank 1
5406 case 20287: spellId
= 25740; break; // Rank 2
5407 case 20288: spellId
= 25739; break; // Rank 3
5408 case 20289: spellId
= 25738; break; // Rank 4
5409 case 20290: spellId
= 25737; break; // Rank 5
5410 case 20291: spellId
= 25736; break; // Rank 6
5411 case 20292: spellId
= 25735; break; // Rank 7
5412 case 20293: spellId
= 25713; break; // Rank 8
5413 case 27155: spellId
= 27156; break; // Rank 9
5415 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5418 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5419 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5421 float damageBasePoints
;
5422 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5424 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5426 // one hand weapon/no weapon
5427 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5429 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5431 // apply damage bonuses manually
5432 if(damagePoint
>= 0)
5433 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5435 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5436 return true; // no hidden cooldown
5438 // Seal of Blood do damage trigger
5439 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5441 switch(triggeredByAura
->GetEffIndex())
5444 // prevent chain triggering
5445 if(procSpell
&& procSpell
->Id
==31893 )
5448 triggered_spell_id
= 31893;
5453 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5455 triggered_spell_id
= 32221;
5461 switch(dummySpell
->Id
)
5463 // Holy Power (Redemption Armor set)
5469 // Set class defined buff
5470 switch (pVictim
->getClass())
5476 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5480 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5484 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5487 triggered_spell_id
= 28790; // Increases the friendly target's armor
5497 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5500 triggered_spell_id
= 31803;
5507 // if healed by another unit (pVictim)
5512 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5514 triggered_spell_id
= 31786;
5517 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5525 // Flash of light/Holy light
5526 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5528 triggered_spell_id
= 40471;
5532 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5534 triggered_spell_id
= 40472;
5540 if (!roll_chance_f(chance
))
5548 case SPELLFAMILY_SHAMAN
:
5550 switch(dummySpell
->Id
)
5552 // Totemic Power (The Earthshatterer set)
5558 // Set class defined buff
5559 switch (pVictim
->getClass())
5565 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5569 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5573 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5576 triggered_spell_id
= 28827; // Increases the friendly target's armor
5583 // Lesser Healing Wave (Totem of Flowing Water Relic)
5587 triggered_spell_id
= 28850;
5590 // Windfury Weapon (Passive) 1-5 Ranks
5593 if(GetTypeId()!=TYPEID_PLAYER
)
5596 if(!castItem
|| !castItem
->IsEquipped())
5599 // custom cooldown processing case
5600 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5604 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5606 case 283: spellId
= 33757; break; //1 Rank
5607 case 284: spellId
= 33756; break; //2 Rank
5608 case 525: spellId
= 33755; break; //3 Rank
5609 case 1669:spellId
= 33754; break; //4 Rank
5610 case 2636:spellId
= 33727; break; //5 Rank
5613 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5614 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5619 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5620 if(!windfurySpellEntry
)
5622 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5626 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5629 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5631 // Value gained from additional AP
5632 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5633 triggered_spell_id
= 33750;
5638 // Value gained from additional AP
5639 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5640 triggered_spell_id
= 25504;
5643 // apply cooldown before cast to prevent processing itself
5645 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5648 for ( uint32 i
= 0; i
<2; ++i
)
5649 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5653 // Shaman Tier 6 Trinket
5660 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5662 triggered_spell_id
= 40465; // Lightning Bolt
5665 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5667 triggered_spell_id
= 40465; // Lesser Healing Wave
5670 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5672 triggered_spell_id
= 40466; // Stormstrike
5678 if (!roll_chance_f(chance
))
5687 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5689 if(GetTypeId() != TYPEID_PLAYER
)
5693 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5695 triggered_spell_id
= 379;
5698 // Lightning Overload
5699 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5701 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5704 // custom cooldown processing case
5705 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5709 // Every Lightning Bolt and Chain Lightning spell have dublicate vs half damage and zero cost
5710 switch (procSpell
->Id
)
5713 case 403: spellId
= 45284; break; // Rank 1
5714 case 529: spellId
= 45286; break; // Rank 2
5715 case 548: spellId
= 45287; break; // Rank 3
5716 case 915: spellId
= 45288; break; // Rank 4
5717 case 943: spellId
= 45289; break; // Rank 5
5718 case 6041: spellId
= 45290; break; // Rank 6
5719 case 10391: spellId
= 45291; break; // Rank 7
5720 case 10392: spellId
= 45292; break; // Rank 8
5721 case 15207: spellId
= 45293; break; // Rank 9
5722 case 15208: spellId
= 45294; break; // Rank 10
5723 case 25448: spellId
= 45295; break; // Rank 11
5724 case 25449: spellId
= 45296; break; // Rank 12
5726 case 421: spellId
= 45297; break; // Rank 1
5727 case 930: spellId
= 45298; break; // Rank 2
5728 case 2860: spellId
= 45299; break; // Rank 3
5729 case 10605: spellId
= 45300; break; // Rank 4
5730 case 25439: spellId
= 45301; break; // Rank 5
5731 case 25442: spellId
= 45302; break; // Rank 6
5733 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5736 // No thread generated mod
5737 SpellModifier
*mod
= new SpellModifier
;
5738 mod
->op
= SPELLMOD_THREAT
;
5740 mod
->type
= SPELLMOD_PCT
;
5741 mod
->spellId
= dummySpell
->Id
;
5743 mod
->lastAffected
= NULL
;
5744 mod
->mask
= 0x0000000000000003LL
;
5746 ((Player
*)this)->AddSpellMod(mod
, true);
5748 // Remove cooldown (Chain Lightning - have Category Recovery time)
5749 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5750 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5752 // Hmmm.. in most case spells alredy set half basepoints but...
5753 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5755 // 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.
5756 // So - no add changes :)
5757 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5759 ((Player
*)this)->AddSpellMod(mod
, false);
5761 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5762 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5772 // processed charge only counting case
5773 if(!triggered_spell_id
)
5776 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5780 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5785 if(!target
|| target
!=this && !target
->isAlive())
5788 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5792 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5794 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5796 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5797 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5802 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5804 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5806 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5807 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5809 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5810 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5811 int32 basepoints0
= 0;
5813 switch(auraSpellInfo
->SpellFamilyName
)
5815 case SPELLFAMILY_GENERIC
:
5817 switch(auraSpellInfo
->Id
)
5819 // Aegis of Preservation
5821 //Aegis Heal (instead non-existed triggered spell)
5822 triggered_spell_id
= 23781;
5825 // Elune's Touch (moonkin mana restore)
5828 // Elune's Touch (instead non-existed triggered spell)
5829 triggered_spell_id
= 33926;
5830 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5837 // only for cast with mana price
5838 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5840 break; // fall through to normal cast
5845 // at melee hit call std triggered spell
5846 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5847 break; // fall through to normal cast
5849 // Mark of Conquest - else (at range hit) called custom case
5850 triggered_spell_id
= 39557;
5856 return true; // nothing to do
5857 // Forgotten Knowledge (Blade of Wizardry)
5859 // only for harmful enemy targeted spell
5860 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5862 break; // fall through to normal cast
5863 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5866 // proc only at non-crit hits
5867 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5869 break; // fall through to normal cast
5871 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5877 //only periodic damage can trigger spell
5879 for(int j
= 0; j
< 3; ++j
)
5881 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5882 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5883 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5892 break; // fall through to normal cast
5894 // Evasive Maneuvers (Commendation of Kael'thas)
5897 // damage taken that reduces below 35% health
5898 // does NOT mean you must have been >= 35% before
5899 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5901 break; // fall through to normal cast
5905 switch(triggered_spell_id
)
5910 // applied only for main target
5911 if(!pVictim
|| pVictim
!= getVictim())
5914 // continue normal case
5917 // Shamanistic Rage triggered spell
5919 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5924 case SPELLFAMILY_MAGE
:
5926 switch(auraSpellInfo
->SpellIconID
)
5930 //Blazing Speed (instead non-existed triggered spell)
5931 triggered_spell_id
= 31643;
5935 switch(auraSpellInfo
->Id
)
5937 // Persistent Shield (Scarab Brooch)
5939 basepoints0
= int32(damage
* 0.15f
);
5944 case SPELLFAMILY_WARRIOR
:
5947 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5949 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5950 //and effect[1]==TriggerSpell
5951 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5953 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5956 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5957 break; // fall through to normal cast
5961 case SPELLFAMILY_WARLOCK
:
5964 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5966 // last case for Hellfire that damage caster also but don't must stun caster
5967 if( pVictim
== this )
5972 switch (triggeredByAura
->GetId())
5974 case 18096: chance
= 13.0f
; break;
5975 case 18073: chance
= 26.0f
; break;
5977 if (!roll_chance_f(chance
))
5980 // Pyroclasm (instead non-existed triggered spell)
5981 triggered_spell_id
= 18093;
5986 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5989 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5990 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5992 //Improved Drain Soul
5993 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5995 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5996 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5999 triggered_spell_id
= 18371;
6007 break; // fall through to normal cast
6011 case SPELLFAMILY_PRIEST
:
6014 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6016 switch (triggeredByAura
->GetSpellProto()->Id
)
6018 case 27811: triggered_spell_id
= 27813; break;
6019 case 27815: triggered_spell_id
= 27817; break;
6020 case 27816: triggered_spell_id
= 27818; break;
6022 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6026 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6027 basepoints0
= heal_amount
/3;
6032 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
[0]==7958)
6034 switch(triggeredByAura
->GetSpellProto()->Id
)
6037 triggered_spell_id
= 28377; break; // Rank 1
6039 triggered_spell_id
= 28378; break; // Rank 2
6041 triggered_spell_id
= 28379; break; // Rank 3
6043 triggered_spell_id
= 28380; break; // Rank 4
6045 triggered_spell_id
= 28381; break; // Rank 5
6047 triggered_spell_id
= 28382; break; // Rank 6
6049 triggered_spell_id
= 28385; break; // Rank 7
6051 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6059 case SPELLFAMILY_DRUID
:
6061 switch(auraSpellInfo
->Id
)
6063 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6066 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6068 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6069 triggered_spell_id
= 34299;
6072 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6079 triggered_spell_id
=37340; break;// Ursine Blessing
6081 triggered_spell_id
=37341; break;// Feline Blessing
6083 triggered_spell_id
=37342; break;// Slyvan Blessing
6085 triggered_spell_id
=37343; break;// Lunar Blessing
6087 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6098 case SPELLFAMILY_ROGUE
:
6100 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6102 switch(auraSpellInfo
->SpellIconID
)
6107 // skip non offhand attacks
6108 if(attackType
!=OFF_ATTACK
)
6110 break; // fall through to normal cast
6116 case SPELLFAMILY_PALADIN
:
6118 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6120 switch(auraSpellInfo
->Id
)
6122 // Lightning Capacitor
6125 // trinket ProcTriggerSpell but for safe checks for player
6126 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6129 if(((Player
*)this)->HasSpellCooldown(37657))
6133 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6134 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6135 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6139 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6140 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6141 if((*itr
)->GetId()==37658)
6144 // release at 3 aura in stack
6146 return true; // main triggered spell casted anyway
6148 RemoveAurasDueToSpell(37658);
6149 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6154 // Healing Trance (instead non-existed triggered spell)
6155 triggered_spell_id
= 37706;
6158 // HoTs on Heals (Fel Reaver's Piston trinket)
6161 // at direct heal effect
6162 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6165 // single proc at time
6166 AuraList
const& scAuras
= GetSingleCastAuras();
6167 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6168 if((*itr
)->GetId()==triggered_spell_id
)
6171 // positive cast at victim instead self
6176 switch(auraSpellInfo
->SpellIconID
)
6180 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6188 // procspell is triggered spell but we need mana cost of original casted spell
6189 uint32 originalSpellId
= procSpell
->Id
;
6192 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6194 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6196 switch(procSpell
->Id
)
6198 case 25914: originalSpellId
= 20473; break;
6199 case 25913: originalSpellId
= 20929; break;
6200 case 25903: originalSpellId
= 20930; break;
6201 case 27175: originalSpellId
= 27174; break;
6202 case 33074: originalSpellId
= 33072; break;
6204 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6210 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6213 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6217 // percent stored in effect 1 (class scripts) base points
6218 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6220 basepoints0
= originalSpell
->manaCost
*percent
/100;
6221 triggered_spell_id
= 20272;
6230 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6232 switch(auraSpellInfo
->SpellIconID
)
6234 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6237 if(!pVictim
|| !pVictim
->isAlive())
6241 switch(triggeredByAura
->GetSpellProto()->Id
)
6244 triggered_spell_id
= 20268; // Rank 1
6247 triggered_spell_id
= 20352; // Rank 2
6250 triggered_spell_id
= 20353; // Rank 3
6253 triggered_spell_id
= 27165; // Rank 4
6256 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6260 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6261 return true; // no hidden cooldown
6263 //Judgement of Light
6266 if(!pVictim
|| !pVictim
->isAlive())
6269 // overwrite non existing triggered spell call in spell.dbc
6271 switch(triggeredByAura
->GetSpellProto()->Id
)
6274 triggered_spell_id
= 20267; // Rank 1
6277 triggered_spell_id
= 20341; // Rank 2
6280 triggered_spell_id
= 20342; // Rank 3
6283 triggered_spell_id
= 20343; // Rank 4
6286 triggered_spell_id
= 27163; // Rank 5
6289 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6292 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6293 return true; // no hidden cooldown
6297 // custom check for proc spell
6298 switch(auraSpellInfo
->Id
)
6300 // Bonus Healing (item spell)
6303 if(!pVictim
|| !pVictim
->isAlive())
6306 // bonus if health < 50%
6307 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6310 // cast at target positive spell
6315 switch(triggered_spell_id
)
6319 // prevent chain of triggered spell from same triggered spell
6320 if(procSpell
&& procSpell
->Id
==20424)
6326 case SPELLFAMILY_SHAMAN
:
6328 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6330 switch(auraSpellInfo
->SpellIconID
)
6334 switch(auraSpellInfo
->Id
)
6336 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6338 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6339 triggered_spell_id
= 23552;
6343 case 23552: // Lightning Shield - trigger shield damage
6345 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6346 triggered_spell_id
= 27635;
6353 // Mana Surge (Shaman T1 bonus)
6359 basepoints0
= procSpell
->manaCost
* 35/100;
6360 triggered_spell_id
= 23571;
6367 if(GetTypeId()!=TYPEID_PLAYER
)
6370 // damage taken that reduces below 30% health
6371 // does NOT mean you must have been >= 30% before
6372 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6375 triggered_spell_id
= 31616;
6377 // need check cooldown now
6378 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6381 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6383 if(pVictim
&& pVictim
->isAlive())
6384 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6390 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6391 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
[0]==7358)
6398 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
[0]==37)
6400 // overwrite non existing triggered spell call in spell.dbc
6401 switch(triggeredByAura
->GetSpellProto()->Id
)
6404 triggered_spell_id
= 26364; break; // Rank 1
6406 triggered_spell_id
= 26365; break; // Rank 2
6408 triggered_spell_id
= 26366; break; // Rank 3
6410 triggered_spell_id
= 26367; break; // Rank 4
6412 triggered_spell_id
= 26369; break; // Rank 5
6414 triggered_spell_id
= 26370; break; // Rank 6
6416 triggered_spell_id
= 26363; break; // Rank 7
6418 triggered_spell_id
= 26371; break; // Rank 8
6420 triggered_spell_id
= 26372; break; // Rank 9
6422 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6433 // standard non-dummy case
6434 if(!triggered_spell_id
)
6436 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6440 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6444 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6448 // not allow proc extra attack spell at extra attack
6449 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6452 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6456 if(!target
|| target
!=this && !target
->isAlive())
6460 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6462 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6464 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6465 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6470 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, int32 scriptId
, uint32 damage
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6472 if(!pVictim
|| !pVictim
->isAlive())
6475 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6476 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6478 uint32 triggered_spell_id
= 0;
6482 case 836: // Improved Blizzard (Rank 1)
6484 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6486 triggered_spell_id
= 12484;
6489 case 988: // Improved Blizzard (Rank 2)
6491 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6493 triggered_spell_id
= 12485;
6496 case 989: // Improved Blizzard (Rank 3)
6498 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6500 triggered_spell_id
= 12486;
6503 case 4086: // Improved Mend Pet (Rank 1)
6504 case 4087: // Improved Mend Pet (Rank 2)
6506 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6507 if(!roll_chance_i(chance
))
6510 triggered_spell_id
= 24406;
6513 case 4533: // Dreamwalker Raiment 2 pieces bonus
6516 if (!roll_chance_i(50))
6519 switch (pVictim
->getPowerType())
6521 case POWER_MANA
: triggered_spell_id
= 28722; break;
6522 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6523 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6529 case 4537: // Dreamwalker Raiment 6 pieces bonus
6530 triggered_spell_id
= 28750; // Blessing of the Claw
6532 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6533 triggered_spell_id
= 37445; // Mana Surge
6538 if(!triggered_spell_id
)
6541 // standard non-dummy case
6542 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6546 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6550 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6553 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6555 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6556 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6561 void Unit::setPowerType(Powers new_powertype
)
6563 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6565 if(GetTypeId() == TYPEID_PLAYER
)
6567 if(((Player
*)this)->GetGroup())
6568 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6570 else if(((Creature
*)this)->isPet())
6572 Pet
*pet
= ((Pet
*)this);
6573 if(pet
->isControlled())
6575 Unit
*owner
= GetOwner();
6576 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6577 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6581 switch(new_powertype
)
6587 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6588 SetPower( POWER_RAGE
,0);
6591 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6592 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6595 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6596 SetPower( POWER_ENERGY
,0);
6598 case POWER_HAPPINESS
:
6599 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6600 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6605 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6607 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6610 static uint64 guid
= 0; // prevent repeating spam same faction problem
6612 if(GetGUID() != guid
)
6614 if(GetTypeId() == TYPEID_PLAYER
)
6615 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6617 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6624 bool Unit::IsHostileTo(Unit
const* unit
) const
6626 // always non-hostile to self
6630 // always non-hostile to GM in GM mode
6631 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6634 // always hostile to enemy
6635 if(getVictim()==unit
|| unit
->getVictim()==this)
6638 // test pet/charm masters instead pers/charmeds
6639 Unit
const* testerOwner
= GetCharmerOrOwner();
6640 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6642 // always hostile to owner's enemy
6643 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6646 // always hostile to enemy owner
6647 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6650 // always hostile to owner of owner's enemy
6651 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6654 Unit
const* tester
= testerOwner
? testerOwner
: this;
6655 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6657 // always non-hostile to target with common owner, or to owner/pet
6661 // special cases (Duel, etc)
6662 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6664 Player
const* pTester
= (Player
const*)tester
;
6665 Player
const* pTarget
= (Player
const*)target
;
6668 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6672 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6676 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6680 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6684 // Green/Blue (can't attack)
6685 if(pTester
->GetTeam()==pTarget
->GetTeam())
6688 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6689 return pTester
->IsPvP() && pTarget
->IsPvP();
6692 // faction base cases
6693 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6694 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6695 if(!tester_faction
|| !target_faction
)
6698 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6701 // PvC forced reaction and reputation case
6702 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6705 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6706 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6707 return forceItr
->second
<= REP_HOSTILE
;
6709 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6710 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6711 if(raw_target_faction
->reputationListID
>=0)
6712 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6713 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6715 // CvP forced reaction and reputation case
6716 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6719 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6720 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6721 return forceItr
->second
<= REP_HOSTILE
;
6723 // apply reputation state
6724 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6725 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6726 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6729 // common faction based case (CvC,PvC,CvP)
6730 return tester_faction
->IsHostileTo(*target_faction
);
6733 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6735 // always friendly to self
6739 // always friendly to GM in GM mode
6740 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6743 // always non-friendly to enemy
6744 if(getVictim()==unit
|| unit
->getVictim()==this)
6747 // test pet/charm masters instead pers/charmeds
6748 Unit
const* testerOwner
= GetCharmerOrOwner();
6749 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6751 // always non-friendly to owner's enemy
6752 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6755 // always non-friendly to enemy owner
6756 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6759 // always non-friendly to owner of owner's enemy
6760 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6763 Unit
const* tester
= testerOwner
? testerOwner
: this;
6764 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6766 // always friendly to target with common owner, or to owner/pet
6770 // special cases (Duel)
6771 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6773 Player
const* pTester
= (Player
const*)tester
;
6774 Player
const* pTarget
= (Player
const*)target
;
6777 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6781 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6785 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6789 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6793 // Green/Blue (non-attackable)
6794 if(pTester
->GetTeam()==pTarget
->GetTeam())
6797 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6798 return !pTarget
->IsPvP();
6801 // faction base cases
6802 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6803 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6804 if(!tester_faction
|| !target_faction
)
6807 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6810 // PvC forced reaction and reputation case
6811 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6814 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6815 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6816 return forceItr
->second
>= REP_FRIENDLY
;
6818 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6819 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6820 if(raw_target_faction
->reputationListID
>=0)
6821 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6822 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6824 // CvP forced reaction and reputation case
6825 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6828 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6829 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6830 return forceItr
->second
>= REP_FRIENDLY
;
6832 // apply reputation state
6833 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6834 if(raw_tester_faction
->reputationListID
>=0 )
6835 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6838 // common faction based case (CvC,PvC,CvP)
6839 return tester_faction
->IsFriendlyTo(*target_faction
);
6842 bool Unit::IsHostileToPlayers() const
6844 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6848 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6849 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6852 return my_faction
->IsHostileToPlayers();
6855 bool Unit::IsNeutralToAll() const
6857 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6861 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6862 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6865 return my_faction
->IsNeutralToAll();
6868 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6870 if(!victim
|| victim
== this)
6873 // dead units can neither attack nor be attacked
6874 if(!isAlive() || !victim
->isAlive())
6877 // player cannot attack in mount state
6878 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6881 // nobody can attack GM in GM-mode
6882 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6884 if(((Player
*)victim
)->isGameMaster())
6889 if(((Creature
*)victim
)->IsInEvadeMode())
6893 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6894 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6895 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6899 if (m_attacking
== victim
)
6901 // switch to melee attack from ranged/magic
6902 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6904 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6905 SendAttackStart(victim
);
6914 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6917 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6918 m_attacking
= victim
;
6919 m_attacking
->_addAttacker(this);
6921 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6922 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6924 if(GetTypeId()==TYPEID_UNIT
)
6926 WorldPacket
data(SMSG_AI_REACTION
, 12);
6927 data
<< uint64(GetGUID());
6928 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6929 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6931 ((Creature
*)this)->CallAssistence();
6932 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6935 // delay offhand weapon attack to next attack time
6936 if(haveOffhandWeapon())
6937 resetAttackTimer(OFF_ATTACK
);
6940 SendAttackStart(victim
);
6945 bool Unit::AttackStop()
6950 Unit
* victim
= m_attacking
;
6952 m_attacking
->_removeAttacker(this);
6956 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6958 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6960 InterruptSpell(CURRENT_MELEE_SPELL
);
6962 if( GetTypeId()==TYPEID_UNIT
)
6964 // reset call assistance
6965 ((Creature
*)this)->SetNoCallAssistence(false);
6968 SendAttackStop(victim
);
6973 void Unit::CombatStop(bool cast
)
6975 if(cast
& IsNonMeleeSpellCasted(false))
6976 InterruptNonMeleeSpells(false);
6979 RemoveAllAttackers();
6980 if( GetTypeId()==TYPEID_PLAYER
)
6981 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6985 void Unit::CombatStopWithPets(bool cast
)
6988 if(Pet
* pet
= GetPet())
6989 pet
->CombatStop(cast
);
6990 if(Unit
* charm
= GetCharm())
6991 charm
->CombatStop(cast
);
6992 if(GetTypeId()==TYPEID_PLAYER
)
6994 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6995 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6996 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6997 guardian
->CombatStop(cast
);
7001 bool Unit::isAttackingPlayer() const
7003 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
7006 Pet
* pet
= GetPet();
7007 if(pet
&& pet
->isAttackingPlayer())
7010 Unit
* charmed
= GetCharm();
7011 if(charmed
&& charmed
->isAttackingPlayer())
7014 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7018 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7019 if(totem
&& totem
->isAttackingPlayer())
7027 void Unit::RemoveAllAttackers()
7029 while (!m_attackers
.empty())
7031 AttackerSet::iterator iter
= m_attackers
.begin();
7032 if(!(*iter
)->AttackStop())
7034 sLog
.outError("WORLD: Unit has an attacker that isnt attacking it!");
7035 m_attackers
.erase(iter
);
7040 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7044 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7046 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7047 if(GetTypeId() == TYPEID_PLAYER
)
7049 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7050 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7052 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7053 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7054 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7055 if (spellInfo
->CasterAuraState
== flag
)
7056 CastSpell(this, itr
->first
, true, NULL
);
7063 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7065 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7066 Unit::AuraMap
& tAuras
= GetAuras();
7067 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7069 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7070 if (spellProto
->CasterAuraState
== flag
)
7072 // exceptions (applied at state but not removed at state change)
7074 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7089 Unit
*Unit::GetOwner() const
7091 uint64 ownerid
= GetOwnerGUID();
7094 return ObjectAccessor::GetUnit(*this, ownerid
);
7097 Unit
*Unit::GetCharmer() const
7099 if(uint64 charmerid
= GetCharmerGUID())
7100 return ObjectAccessor::GetUnit(*this, charmerid
);
7104 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7106 uint64 guid
= GetCharmerOrOwnerGUID();
7107 if(IS_PLAYER_GUID(guid
))
7108 return ObjectAccessor::GetPlayer(*this, guid
);
7110 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7113 Pet
* Unit::GetPet() const
7115 if(uint64 pet_guid
= GetPetGUID())
7117 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7120 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7121 const_cast<Unit
*>(this)->SetPet(0);
7127 Unit
* Unit::GetCharm() const
7129 if(uint64 charm_guid
= GetCharmGUID())
7131 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7134 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7135 const_cast<Unit
*>(this)->SetCharm(0);
7141 void Unit::SetPet(Pet
* pet
)
7143 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7145 // FIXME: hack, speed must be set only at follow
7147 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7148 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
7151 void Unit::SetCharm(Unit
* charmed
)
7153 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7156 void Unit::UnsummonAllTotems()
7158 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7163 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7164 if (OldTotem
&& OldTotem
->isTotem())
7165 ((Totem
*)OldTotem
)->UnSummon();
7169 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7172 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7173 data
.append(pVictim
->GetPackGUID());
7174 data
.append(GetPackGUID());
7175 data
<< uint32(SpellID
);
7176 data
<< uint32(Damage
);
7177 data
<< uint32(0); // over healing?
7178 data
<< uint8(critical
? 1 : 0);
7179 data
<< uint8(0); // unused in client?
7180 SendMessageToSet(&data
, true);
7183 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
, bool critical
)
7185 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7186 data
.append(pVictim
->GetPackGUID());
7187 data
.append(GetPackGUID());
7188 data
<< uint32(SpellID
);
7189 data
<< uint32(powertype
);
7190 data
<< uint32(Damage
);
7191 SendMessageToSet(&data
, true);
7194 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7196 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7199 int32 BonusDamage
= 0;
7200 if( GetTypeId()==TYPEID_UNIT
)
7202 // Pets just add their bonus damage to their spell damage
7203 // note that their spell damage is just gain of their own auras
7204 if (((Creature
*)this)->isPet())
7206 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7208 // For totems get damage bonus from owner (statue isn't totem in fact)
7209 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7211 if(Unit
* owner
= GetOwner())
7212 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7217 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7219 // Taken/Done fixed damage bonus auras
7220 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7221 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7223 // Damage over Time spells bonus calculation
7224 float DotFactor
= 1.0f
;
7225 if(damagetype
== DOT
)
7227 int32 DotDuration
= GetSpellDuration(spellProto
);
7231 if(DotDuration
> 30000) DotDuration
= 30000;
7232 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7234 for(int j
= 0; j
< 3; j
++)
7236 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7237 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7238 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7245 if(spellProto
->EffectAmplitude
[x
] != 0)
7246 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7249 DoneAdvertisedBenefit
/= DotTicks
;
7250 TakenAdvertisedBenefit
/= DotTicks
;
7255 // Taken/Done total percent damage auras
7256 float DoneTotalMod
= 1.0f
;
7257 float TakenTotalMod
= 1.0f
;
7260 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7261 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7263 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7264 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7265 // -1 == any item class (not wand then)
7266 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7267 // 0 == any inventory type (not wand then)
7269 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7273 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7274 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7275 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7276 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7277 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7280 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7281 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7282 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7283 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7285 // .. taken pct: scripted (increases damage of * against targets *)
7286 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7287 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7289 switch((*i
)->GetModifier()->m_miscvalue
)
7292 case 4920: case 4919:
7293 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7294 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7298 // .. taken pct: dummy auras
7299 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7300 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7302 switch((*i
)->GetSpellProto()->SpellIconID
)
7306 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7308 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7310 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7311 if (mod
< (*i
)->GetModifier()->m_amount
)
7312 mod
= (*i
)->GetModifier()->m_amount
;
7313 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7318 for(int j
=0;j
<3;j
++)
7320 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7322 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7330 // Distribute Damage over multiple effects, reduce by AoE
7331 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7333 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7334 for(int j
= 0; j
< 3; ++j
)
7336 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7337 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7344 switch(spellProto
->SpellFamilyName
)
7346 case SPELLFAMILY_MAGE
:
7347 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7348 if(spellProto
->Id
==12654)
7353 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7355 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7356 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7357 TakenTotalMod
*= 3.0f
;
7359 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7360 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7362 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7363 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7365 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7366 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7369 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7372 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7376 // Arcane Missiles triggered spell
7377 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7381 // Blizzard triggered spell
7382 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7387 case SPELLFAMILY_WARLOCK
:
7389 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7391 CastingTime
= 2800; // 80% from +shadow damage
7392 DoneTotalMod
= 1.0f
;
7393 TakenTotalMod
= 1.0f
;
7396 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7398 CastingTime
= 3360; // 96% from +shadow damage
7399 DoneTotalMod
= 1.0f
;
7400 TakenTotalMod
= 1.0f
;
7402 // Soul Fire - 115% of Fire Damage
7403 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7407 // Curse of Agony - 120% of Shadow Damage
7408 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7412 // Drain Mana - 0% of Shadow Damage
7413 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7417 // Drain Soul 214.3%
7418 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7423 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7425 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7427 // Unstable Affliction - 180%
7428 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7433 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7438 case SPELLFAMILY_PALADIN
:
7439 // Consecration - 95% of Holy Damage
7440 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7445 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7446 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7448 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7449 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7451 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7452 CastingTime
= uint32(wspeed
*3500*0.102f
);
7454 CastingTime
= uint32(wspeed
*3500*0.098f
);
7456 // Judgement of Righteousness - 73%
7457 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7461 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7462 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7467 // Holy shield - 5% of Holy Damage
7468 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7472 // Blessing of Sanctuary - 0%
7473 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7477 // Seal of Righteousness trigger - already computed for parent spell
7478 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7483 case SPELLFAMILY_SHAMAN
:
7485 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7487 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7488 CastingTime
= 749; // ignore CastingTime and use as modifier
7489 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7490 CastingTime
= 280; // ignore CastingTime and use as modifier
7491 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7492 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7494 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7495 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7496 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7498 case SPELLFAMILY_PRIEST
:
7499 // Mana Burn - 0% of Shadow Damage
7500 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7504 // Mind Flay - 59% of Shadow Damage
7505 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7509 // Holy Fire - 86.71%, DoT - 16.5%
7510 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7512 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7513 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7515 // Shadowguard - 28% per charge
7516 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7520 // Touch of Weakeness - 10%
7521 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7525 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7526 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7531 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7536 case SPELLFAMILY_DRUID
:
7537 // Hurricane triggered spell
7538 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7543 case SPELLFAMILY_WARRIOR
:
7544 case SPELLFAMILY_HUNTER
:
7545 case SPELLFAMILY_ROGUE
:
7552 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7554 // Spellmod SpellDamage
7555 float SpellModSpellDamage
= 100.0f
;
7557 if(Player
* modOwner
= GetSpellModOwner())
7558 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7560 SpellModSpellDamage
/= 100.0f
;
7562 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7563 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7565 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7567 // Add flat bonus from spell damage versus
7568 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7570 // apply spellmod to Done damage
7571 if(Player
* modOwner
= GetSpellModOwner())
7572 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7574 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7576 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7577 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7579 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7582 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7584 int32 DoneAdvertisedBenefit
= 0;
7587 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7588 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7589 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7590 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7591 // -1 == any item class (not wand then)
7592 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7593 // 0 == any inventory type (not wand then)
7594 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7596 if (GetTypeId() == TYPEID_PLAYER
)
7598 // Damage bonus from stats
7599 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7600 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7602 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7604 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7605 uint8 eff
= (*i
)->GetEffIndex();
7607 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7608 Stats usedStat
= STAT_INTELLECT
;
7609 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7610 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7612 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7615 // ... and attack power
7616 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7617 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7618 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7619 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7622 return DoneAdvertisedBenefit
;
7625 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7627 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7629 int32 TakenAdvertisedBenefit
= 0;
7630 // ..done (for creature type by mask) in taken
7631 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7632 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7633 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7634 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7637 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7638 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7639 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7640 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7642 return TakenAdvertisedBenefit
;
7645 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7647 // not critting spell
7648 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7651 float crit_chance
= 0.0f
;
7652 switch(spellProto
->DmgClass
)
7654 case SPELL_DAMAGE_CLASS_NONE
:
7656 case SPELL_DAMAGE_CLASS_MAGIC
:
7658 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7660 // For other schools
7661 else if (GetTypeId() == TYPEID_PLAYER
)
7662 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7665 crit_chance
= m_baseSpellCritChance
;
7666 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7669 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7671 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7672 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7673 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7674 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7675 // Modify by player victim resilience
7676 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7677 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7678 // scripted (increase crit chance ... against ... target by x%
7679 if(pVictim
->isFrozen()) // Shatter
7681 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7682 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7684 switch((*i
)->GetModifier()->m_miscvalue
)
7686 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7687 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7688 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7689 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7690 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7697 case SPELL_DAMAGE_CLASS_MELEE
:
7698 case SPELL_DAMAGE_CLASS_RANGED
:
7702 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7703 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7704 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7712 // only players use intelligence for critical chance computations
7713 if(Player
* modOwner
= GetSpellModOwner())
7714 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7716 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7717 if (roll_chance_f(crit_chance
))
7722 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7724 // Calculate critical bonus
7726 switch(spellProto
->DmgClass
)
7728 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7729 case SPELL_DAMAGE_CLASS_RANGED
:
7730 // TODO: write here full calculation for melee/ranged spells
7731 crit_bonus
= damage
;
7734 crit_bonus
= damage
/ 2; // for spells is 50%
7738 // adds additional damage to crit_bonus (from talents)
7739 if(Player
* modOwner
= GetSpellModOwner())
7740 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7744 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7745 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7749 damage
+= crit_bonus
;
7754 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7756 // For totems get healing bonus from owner (statue isn't totem in fact)
7757 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7758 if(Unit
* owner
= GetOwner())
7759 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7763 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7764 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7765 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7766 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7769 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7770 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7773 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7775 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7776 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7778 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7779 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7781 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7784 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7785 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7787 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7788 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7793 float ActualBenefit
= 0.0f
;
7795 if (AdvertisedBenefit
!= 0)
7797 // Healing over Time spells
7798 float DotFactor
= 1.0f
;
7799 if(damagetype
== DOT
)
7801 int32 DotDuration
= GetSpellDuration(spellProto
);
7805 if(DotDuration
> 30000) DotDuration
= 30000;
7806 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7808 for(int j
= 0; j
< 3; j
++)
7810 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7811 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7812 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7819 if(spellProto
->EffectAmplitude
[x
] != 0)
7820 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7822 AdvertisedBenefit
/= DotTicks
;
7826 // distribute healing to all effects, reduce AoE damage
7827 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7829 // 0% bonus for damage and healing spells for leech spells from healing bonus
7830 for(int j
= 0; j
< 3; ++j
)
7832 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7833 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7841 switch (spellProto
->SpellFamilyName
)
7843 case SPELLFAMILY_SHAMAN
:
7844 // Healing stream from totem (add 6% per tick from hill bonus owner)
7845 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7847 // Earth Shield 30% per charge
7848 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7851 case SPELLFAMILY_DRUID
:
7853 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7855 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7856 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7858 // Tranquility triggered spell
7859 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7862 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7865 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7867 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7868 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7871 case SPELLFAMILY_PRIEST
:
7873 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7876 case SPELLFAMILY_PALADIN
:
7877 // Seal and Judgement of Light
7878 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7881 case SPELLFAMILY_WARRIOR
:
7882 case SPELLFAMILY_ROGUE
:
7883 case SPELLFAMILY_HUNTER
:
7888 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7890 // Spellmod SpellDamage
7891 float SpellModSpellDamage
= 100.0f
;
7893 if(Player
* modOwner
= GetSpellModOwner())
7894 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7896 SpellModSpellDamage
/= 100.0f
;
7898 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7901 // use float as more appropriate for negative values and percent applying
7902 float heal
= healamount
+ ActualBenefit
;
7904 // TODO: check for ALL/SPELLS type
7905 // Healing done percent
7906 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7907 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7908 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7910 // apply spellmod to Done amount
7911 if(Player
* modOwner
= GetSpellModOwner())
7912 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7914 // Healing Wave cast
7915 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7917 // Search for Healing Way on Victim (stack up to 3 time)
7919 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7920 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7921 if((*itr
)->GetId() == 29203)
7922 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7925 heal
= heal
* (100 + pctMod
) / 100;
7928 // Healing taken percent
7929 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7931 heal
*= (100.0f
+ minval
) / 100.0f
;
7933 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7935 heal
*= (100.0f
+ maxval
) / 100.0f
;
7937 if (heal
< 0) heal
= 0;
7939 return uint32(heal
);
7942 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7944 int32 AdvertisedBenefit
= 0;
7946 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7947 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7948 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7949 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7951 // Healing bonus of spirit, intellect and strength
7952 if (GetTypeId() == TYPEID_PLAYER
)
7954 // Healing bonus from stats
7955 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7956 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7958 // stat used dependent from misc value (stat index)
7959 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7960 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7963 // ... and attack power
7964 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7965 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7966 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7967 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7969 return AdvertisedBenefit
;
7972 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7974 int32 AdvertisedBenefit
= 0;
7975 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7976 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7977 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7978 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7979 return AdvertisedBenefit
;
7982 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7984 // no charges dependent checks
7985 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7986 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7987 if(itr
->type
& shoolMask
)
7990 // charges dependent checks
7991 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7992 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7994 if(itr
->type
& shoolMask
)
7998 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7999 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
8001 if((*auraItr
)->GetId()==itr
->spellId
)
8003 if((*auraItr
)->m_procCharges
> 0)
8005 --(*auraItr
)->m_procCharges
;
8006 if((*auraItr
)->m_procCharges
==0)
8007 RemoveAurasDueToSpell(itr
->spellId
);
8020 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8027 //FIX ME this hack: don't get feared if stunned
8028 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8030 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8034 // not have spells with charges currently
8035 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8036 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8037 if(itr
->type
== spellInfo
->Dispel
)
8040 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8042 // not have spells with charges currently
8043 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8044 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8045 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8046 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8050 // charges dependent checks
8052 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8053 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8055 if(itr
->type
== spellInfo
->Mechanic
)
8059 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8060 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8062 if((*auraItr
)->GetId()==itr
->spellId
)
8064 if((*auraItr
)->m_procCharges
> 0)
8066 --(*auraItr
)->m_procCharges
;
8067 if((*auraItr
)->m_procCharges
==0)
8068 RemoveAurasDueToSpell(itr
->spellId
);
8081 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8083 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8084 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8085 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8086 if(itr
->type
== effect
)
8089 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8090 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8091 if(itr
->type
== mechanic
)
8097 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8102 uint32 family
= spellInfo
->SpellFamilyName
;
8103 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8105 if((family
== 5 && flags
== 256) || //Searing Pain
8106 (family
== 6 && flags
== 8192) || //Mind Blast
8107 (family
== 11 && flags
== 1048576)) //Earth Shock
8113 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8121 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8123 // Taken/Done fixed damage bonus auras
8124 int32 DoneFlatBenefit
= 0;
8125 int32 TakenFlatBenefit
= 0;
8127 // ..done (for creature type by mask) in taken
8128 AuraList
const& mDamageDoneCreature
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8129 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8130 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8131 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8134 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8136 // ..done (base at attack power for marked target and base at attack power for creature type)
8138 if(attType
== RANGED_ATTACK
)
8140 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8142 // ..done (base at attack power and creature type)
8143 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8144 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8145 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8146 APbonus
+= (*i
)->GetModifier()->m_amount
;
8150 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8152 // ..done (base at attack power and creature type)
8153 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8154 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8155 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8156 APbonus
+= (*i
)->GetModifier()->m_amount
;
8159 if (APbonus
!=0) // Can be negative
8161 bool normalized
= false;
8164 for (uint8 i
= 0; i
<3;i
++)
8166 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8174 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8178 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8179 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8180 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8181 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8183 if(attType
!=RANGED_ATTACK
)
8184 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8186 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8188 // Done/Taken total percent damage auras
8189 float DoneTotalMod
= 1;
8190 float TakenTotalMod
= 1;
8193 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8194 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8196 AuraList
const& mDamageDoneVersus
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8197 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8198 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8199 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8202 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8203 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8204 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8205 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8207 // .. taken pct: dummy auras
8208 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8209 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8211 switch((*i
)->GetSpellProto()->SpellIconID
)
8215 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8217 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8219 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8220 if (mod
< (*i
)->GetModifier()->m_amount
)
8221 mod
= (*i
)->GetModifier()->m_amount
;
8222 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8227 if(spellProto
==NULL
)
8229 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8230 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8231 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8236 // .. taken pct: class scripts
8237 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8238 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8240 switch((*i
)->GetMiscValue())
8242 case 6427: case 6428: // Dirty Deeds
8243 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8245 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8246 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8248 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8252 // effect 0 have expected value but in negative state
8253 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8259 if(attType
!= RANGED_ATTACK
)
8261 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8262 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8263 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8267 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8268 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8269 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8272 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8274 // apply spellmod to Done damage
8277 if(Player
* modOwner
= GetSpellModOwner())
8278 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8281 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8283 // bonus result can be negative
8284 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8287 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8291 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8294 if(itr
->type
== type
)
8296 m_spellImmune
[op
].erase(itr
);
8297 next
= m_spellImmune
[op
].begin();
8301 Immune
.spellId
= spellId
;
8303 m_spellImmune
[op
].push_back(Immune
);
8307 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8309 if(itr
->spellId
== spellId
)
8311 m_spellImmune
[op
].erase(itr
);
8319 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8321 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8323 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8324 RemoveAurasWithDispelType(type
);
8327 float Unit::GetWeaponProcChance() const
8329 // normalized proc chance for weapon attack speed
8331 if(isAttackReady(BASE_ATTACK
))
8332 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8333 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8334 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8338 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8340 // proc per minute chance calculation
8341 if (PPM
<= 0) return 0.0f
;
8342 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8346 void Unit::Mount(uint32 mount
)
8351 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8353 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8355 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8358 if(GetTypeId() == TYPEID_PLAYER
)
8360 Pet
* pet
= GetPet();
8363 if(pet
->isControlled())
8365 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8366 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8369 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8372 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8376 void Unit::Unmount()
8381 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8383 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8384 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8386 // only resummon old pet if the player is already added to a map
8387 // this prevents adding a pet to a not created map which would otherwise cause a crash
8388 // (it could probably happen when logging in after a previous crash)
8389 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8391 Pet
* NewPet
= new Pet
;
8392 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8395 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8399 void Unit::SetInCombatWith(Unit
* enemy
)
8401 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8404 SetInCombatState(true);
8409 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8411 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8412 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8414 SetInCombatState(true);
8418 SetInCombatState(false);
8421 void Unit::SetInCombatState(bool PvP
)
8423 // only alive units can be in combat
8428 m_CombatTimer
= 5000;
8429 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8431 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8432 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8435 void Unit::ClearInCombat()
8438 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8440 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8441 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8443 // Player's state will be cleared in Player::UpdateContestedPvP
8444 if(GetTypeId()!=TYPEID_PLAYER
)
8445 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8448 bool Unit::isTargetableForAttack() const
8450 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8453 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8456 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8459 int32
Unit::ModifyHealth(int32 dVal
)
8466 int32 curHealth
= (int32
)GetHealth();
8468 int32 val
= dVal
+ curHealth
;
8475 int32 maxHealth
= (int32
)GetMaxHealth();
8480 gain
= val
- curHealth
;
8482 else if(curHealth
!= maxHealth
)
8484 SetHealth(maxHealth
);
8485 gain
= maxHealth
- curHealth
;
8491 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8498 int32 curPower
= (int32
)GetPower(power
);
8500 int32 val
= dVal
+ curPower
;
8507 int32 maxPower
= (int32
)GetMaxPower(power
);
8511 SetPower(power
,val
);
8512 gain
= val
- curPower
;
8514 else if(curPower
!= maxPower
)
8516 SetPower(power
,maxPower
);
8517 gain
= maxPower
- curPower
;
8523 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8528 // Always can see self
8532 // player visible for other player if not logout and at same transport
8533 // including case when player is out of world
8534 bool at_same_transport
=
8535 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8536 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8537 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8538 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8541 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8544 // forbidden to seen (at GM respawn command)
8545 if(m_Visibility
==VISIBILITY_RESPAWN
)
8548 // always seen by owner
8549 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8552 // Grid dead/alive checks
8553 if( u
->GetTypeId()==TYPEID_PLAYER
)
8555 // non visible at grid for any stealth state
8556 if(!IsVisibleInGridForPlayer((Player
*)u
))
8559 // if player is dead then he can't detect anyone in anycases
8565 // all dead creatures/players not visible for any creatures
8566 if(!u
->isAlive() || !isAlive())
8570 // different visible distance checks
8571 if(u
->isInFlight()) // what see player in flight
8573 // use object grey distance for all (only see objects any way)
8574 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8577 else if(!isAlive()) // distance for show body
8579 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8582 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8584 if(u
->GetTypeId()==TYPEID_PLAYER
)
8586 // Players far than max visible distance for player or not in our map are not visible too
8587 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8592 // Units far than max visible distance for creature or not in our map are not visible too
8593 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8597 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8599 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8600 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8603 else // distance for show creature
8605 // Units far than max visible distance for creature or not in our map are not visible too
8606 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8610 // Visible units, always are visible for all units, except for units under invisibility
8611 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8614 // GMs see any players, not higher GMs and all units
8615 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8617 if(GetTypeId() == TYPEID_PLAYER
)
8618 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8623 // non faction visibility non-breakable for non-GMs
8624 if (m_Visibility
== VISIBILITY_OFF
)
8628 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8630 // detectable invisibility case
8632 // Invisible units, always are visible for units under same invisibility type
8633 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8634 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8635 u
->canDetectInvisibilityOf(this) ||
8636 // Units that can detect invisibility always are visible for units that can be detected
8637 canDetectInvisibilityOf(u
) ))
8642 // special cases for always overwrite invisibility/stealth
8643 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8646 if (!u
->IsHostileTo(this))
8648 // 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)
8649 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8651 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8654 // else apply same rules as for hostile case (detecting check for stealth)
8660 // Hunter mark functionality
8661 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8662 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8663 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8666 // else apply detecting check for stealth
8669 // none other cases for detect invisibility, so invisible
8673 // else apply stealth detecting check
8676 // unit got in stealth in this moment and must ignore old detected state
8677 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8680 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8681 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8684 // NOW ONLY STEALTH CASE
8686 // stealth and detected and visible for some seconds
8687 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8690 //if in non-detect mode then invisible for unit
8696 // If is attacked then stealth is lost, some creature can use stealth too
8697 if( !getAttackers().empty() )
8700 // If there is collision rogue is seen regardless of level difference
8701 // TODO: check sizes in DB
8702 float distance
= GetDistance(u
);
8703 if (distance
< 0.24f
)
8706 //If a mob or player is stunned he will not be able to detect stealth
8707 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8710 // Creature can detect target only in aggro radius
8711 if(u
->GetTypeId() != TYPEID_PLAYER
)
8713 //Always invisible from back and out of aggro range
8714 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8720 //Always invisible from back
8721 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8726 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8727 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8729 //Calculation if target is in front
8731 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8732 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8734 //Visible distance is modified by
8735 //-Level Diff (every level diff = 1.0f in visible distance)
8736 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(this->getLevelForTarget(u
));
8738 //This allows to check talent tree and will add addition stealth dependent on used points)
8739 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8743 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8744 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8745 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8747 if(distance
> visibleDistance
)
8751 // Now check is target visible with LoS
8753 u
->GetPosition(ox
,oy
,oz
);
8754 return IsWithinLOS(ox
,oy
,oz
);
8757 void Unit::SetVisibility(UnitVisibility x
)
8763 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8765 if(GetTypeId()==TYPEID_PLAYER
)
8766 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8768 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8772 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8774 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8776 for(uint32 i
= 0; i
< 10; ++i
)
8778 if(((1 << i
) & mask
)==0)
8781 // find invisibility level
8782 uint32 invLevel
= 0;
8783 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8784 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8785 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8786 invLevel
= (*itr
)->GetModifier()->m_amount
;
8788 // find invisibility detect level
8789 uint32 detectLevel
= 0;
8790 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8791 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8792 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8793 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8795 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8797 detectLevel
= ((Player
*)this)->GetDrunkValue();
8800 if(invLevel
<= detectLevel
)
8808 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8810 int32 main_speed_mod
= 0;
8811 float stack_bonus
= 1.0f
;
8812 float non_stack_bonus
= 1.0f
;
8820 if (IsMounted()) // Use on mount auras
8822 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8823 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8824 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8828 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8829 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8830 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8838 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8845 if (IsMounted()) // Use on mount auras
8846 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8847 else // Use not mount (shapeshift for example) auras (should stack)
8848 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8849 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8850 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8856 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8860 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8861 // now we ready for speed calculation
8862 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8870 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8871 // TODO: possible affect only on MOVE_RUN
8872 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8874 // Use speed from aura
8875 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8876 if (speed
> max_speed
)
8885 // Apply strongest slow aura mod to speed
8886 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8888 speed
*=(100.0f
+ slow
)/100.0f
;
8889 SetSpeed(mtype
, speed
, forced
);
8892 float Unit::GetSpeed( UnitMoveType mtype
) const
8894 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8897 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8902 // Update speed only on change
8903 if (m_speed_rate
[mtype
] == rate
)
8906 m_speed_rate
[mtype
] = rate
;
8908 propagateSpeedChange();
8910 // Send speed change packet only for player
8911 if (GetTypeId()!=TYPEID_PLAYER
)
8920 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8923 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8926 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8929 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8932 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8935 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8938 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8941 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8944 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8948 data
.append(GetPackGUID());
8949 data
<< uint32(0); //movement flags
8950 data
<< uint16(0); //unk
8951 data
<< uint32(getMSTime());
8952 data
<< float(GetPositionX());
8953 data
<< float(GetPositionY());
8954 data
<< float(GetPositionZ());
8955 data
<< float(GetOrientation());
8956 data
<< uint32(0); //flag unk
8957 data
<< float(GetSpeed(mtype
));
8958 SendMessageToSet( &data
, true );
8962 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8963 // and do it only for real sent packets and use run for run/mounted as client expected
8964 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8968 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8971 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8974 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8977 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8980 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8983 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8986 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8989 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8992 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8995 data
.append(GetPackGUID());
8997 if (mtype
== MOVE_RUN
)
8998 data
<< uint8(0); // new 2.1.0
8999 data
<< float(GetSpeed(mtype
));
9000 SendMessageToSet( &data
, true );
9002 if(Pet
* pet
= GetPet())
9003 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9006 void Unit::SetHover(bool on
)
9009 CastSpell(this,11010,true);
9011 RemoveAurasDueToSpell(11010);
9014 void Unit::setDeathState(DeathState s
)
9016 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9020 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9022 if(IsNonMeleeSpellCasted(false))
9023 InterruptNonMeleeSpells(false);
9028 RemoveAllAurasOnDeath();
9029 UnsummonAllTotems();
9031 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9032 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9033 // remove aurastates allowing special moves
9034 ClearAllReactives();
9035 ClearDiminishings();
9037 else if(s
== JUST_ALIVED
)
9039 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9042 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9044 //_ApplyAllAuraMods();
9049 /*########################################
9051 ######## AGGRO SYSTEM ########
9053 ########################################*/
9054 bool Unit::CanHaveThreatList() const
9056 // only creatures can have threat list
9057 if( GetTypeId() != TYPEID_UNIT
)
9060 // only alive units can have threat list
9064 // pets and totems can not have threat list
9065 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() )
9071 //======================================================================
9073 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9075 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9078 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9080 return threat
* m_threatModifier
[school
];
9083 //======================================================================
9085 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9087 // Only mobs can manage threat lists
9088 if(CanHaveThreatList())
9089 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9092 //======================================================================
9094 void Unit::DeleteThreatList()
9096 m_ThreatManager
.clearReferences();
9099 //======================================================================
9101 void Unit::TauntApply(Unit
* taunter
)
9103 assert(GetTypeId()== TYPEID_UNIT
);
9105 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9108 if(!CanHaveThreatList())
9111 Unit
*target
= getVictim();
9112 if(target
&& target
== taunter
)
9115 SetInFront(taunter
);
9116 if (((Creature
*)this)->AI())
9117 ((Creature
*)this)->AI()->AttackStart(taunter
);
9119 m_ThreatManager
.tauntApply(taunter
);
9122 //======================================================================
9124 void Unit::TauntFadeOut(Unit
*taunter
)
9126 assert(GetTypeId()== TYPEID_UNIT
);
9128 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9131 if(!CanHaveThreatList())
9134 Unit
*target
= getVictim();
9135 if(!target
|| target
!= taunter
)
9138 if(m_ThreatManager
.isThreatListEmpty())
9140 if(((Creature
*)this)->AI())
9141 ((Creature
*)this)->AI()->EnterEvadeMode();
9145 m_ThreatManager
.tauntFadeOut(taunter
);
9146 target
= m_ThreatManager
.getHostilTarget();
9148 if (target
&& target
!= taunter
)
9151 if (((Creature
*)this)->AI())
9152 ((Creature
*)this)->AI()->AttackStart(target
);
9156 //======================================================================
9158 bool Unit::SelectHostilTarget()
9160 //function provides main threat functionality
9161 //next-victim-selection algorithm and evade mode are called
9162 //threat list sorting etc.
9164 assert(GetTypeId()== TYPEID_UNIT
);
9165 Unit
* target
= NULL
;
9167 //This function only useful once AI has been initilazied
9168 if (!((Creature
*)this)->AI())
9171 if(!m_ThreatManager
.isThreatListEmpty())
9173 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9175 target
= m_ThreatManager
.getHostilTarget();
9181 if(!hasUnitState(UNIT_STAT_STUNNED
))
9183 ((Creature
*)this)->AI()->AttackStart(target
);
9187 // no target but something prevent go to evade mode
9188 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9191 // last case when creature don't must go to evade mode:
9192 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9193 // for example at owner command to pet attack some far away creature
9194 // Note: creature not have targeted movement generator but have attacker in this case
9195 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9197 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9199 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9204 // enter in evade mode in other case
9205 ((Creature
*)this)->AI()->EnterEvadeMode();
9210 //======================================================================
9211 //======================================================================
9212 //======================================================================
9214 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9216 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9218 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9220 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9221 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9222 level
= spellProto
->maxLevel
;
9224 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9225 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9226 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9227 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9228 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9230 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9231 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9232 int32 value
= basePoints
+ randvalue
;
9234 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9235 value
+= (int32
)(comboDamage
* comboPoints
);
9237 if(Player
* modOwner
= GetSpellModOwner())
9239 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9240 switch(effect_index
)
9243 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9246 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9249 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9254 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9255 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9256 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9257 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9262 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9264 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9266 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9268 int32 minduration
= GetSpellDuration(spellProto
);
9269 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9273 if( minduration
!= -1 && minduration
!= maxduration
)
9274 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9276 duration
= minduration
;
9280 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9281 // Find total mod value (negative bonus)
9282 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9283 // Find max mod (negative bonus)
9284 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9286 int32 durationMod
= 0;
9287 // Select strongest negative mod
9288 if (durationMod_always
> durationMod_not_stack
)
9289 durationMod
= durationMod_not_stack
;
9291 durationMod
= durationMod_always
;
9293 if (durationMod
!= 0)
9294 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9296 if (duration
< 0) duration
= 0;
9302 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9304 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9306 if(i
->DRGroup
!= group
)
9310 return DIMINISHING_LEVEL_1
;
9313 return DIMINISHING_LEVEL_1
;
9315 // If last spell was casted more than 15 seconds ago - reset the count.
9316 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9318 i
->hitCount
= DIMINISHING_LEVEL_1
;
9319 return DIMINISHING_LEVEL_1
;
9321 // or else increase the count.
9324 return DiminishingLevels(i
->hitCount
);
9327 return DIMINISHING_LEVEL_1
;
9330 void Unit::IncrDiminishing(DiminishingGroup group
)
9332 // Checking for existing in the table
9333 bool IsExist
= false;
9334 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9336 if(i
->DRGroup
!= group
)
9340 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9347 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9350 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9352 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9355 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9356 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9358 // test pet/charm masters instead pets/charmeds
9359 Unit
const* targetOwner
= GetCharmerOrOwner();
9360 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9362 Unit
const* target
= targetOwner
? targetOwner
: this;
9363 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9365 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9371 // Some diminishings applies to mobs too (for example, Stun)
9372 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9374 DiminishingLevels diminish
= Level
;
9377 case DIMINISHING_LEVEL_1
: break;
9378 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9379 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9380 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9385 duration
= int32(duration
* mod
);
9388 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9390 // Checking for existing in the table
9391 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9393 if(i
->DRGroup
!= group
)
9396 i
->hitTime
= getMSTime();
9407 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9409 return ObjectAccessor::GetUnit(object
,guid
);
9412 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9414 return isVisibleForOrDetect(u
,false,inVisibleList
);
9417 uint32
Unit::GetCreatureType() const
9419 if(GetTypeId() == TYPEID_PLAYER
)
9421 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9422 if(ssEntry
&& ssEntry
->creatureType
> 0)
9423 return ssEntry
->creatureType
;
9425 return CREATURE_TYPE_HUMANOID
;
9428 return ((Creature
*)this)->GetCreatureInfo()->type
;
9431 /*#######################################
9433 ######## STAT SYSTEM ########
9435 #######################################*/
9437 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9439 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9441 sLog
.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
9447 switch(modifierType
)
9451 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9455 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9458 val
= (100.0f
+ amount
) / 100.0f
;
9459 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9466 if(!CanModifyStats())
9471 case UNIT_MOD_STAT_STRENGTH
:
9472 case UNIT_MOD_STAT_AGILITY
:
9473 case UNIT_MOD_STAT_STAMINA
:
9474 case UNIT_MOD_STAT_INTELLECT
:
9475 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9477 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9478 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9482 case UNIT_MOD_FOCUS
:
9483 case UNIT_MOD_ENERGY
:
9484 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9486 case UNIT_MOD_RESISTANCE_HOLY
:
9487 case UNIT_MOD_RESISTANCE_FIRE
:
9488 case UNIT_MOD_RESISTANCE_NATURE
:
9489 case UNIT_MOD_RESISTANCE_FROST
:
9490 case UNIT_MOD_RESISTANCE_SHADOW
:
9491 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9493 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9494 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9496 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9497 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9498 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9507 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9509 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9511 sLog
.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
9515 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9518 return m_auraModifiersGroup
[unitMod
][modifierType
];
9521 float Unit::GetTotalStatValue(Stats stat
) const
9523 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9525 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9528 // value = ((base_value * base_pct) + total_value) * total_pct
9529 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9530 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9531 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9532 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9537 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9539 if(unitMod
>= UNIT_MOD_END
)
9541 sLog
.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
9545 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9548 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9549 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9550 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9551 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9556 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9558 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9562 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9563 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9564 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9565 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9566 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9567 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9576 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9578 Stats stat
= STAT_STRENGTH
;
9582 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9583 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9584 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9585 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9586 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9595 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9597 Powers power
= POWER_MANA
;
9601 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9602 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9603 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9604 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9605 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9614 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9616 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9618 float val
= GetTotalAuraModValue(unitMod
);
9625 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9627 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9630 return m_weaponDamage
[attType
][type
];
9633 void Unit::SetLevel(uint32 lvl
)
9635 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9638 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9639 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9642 void Unit::SetHealth(uint32 val
)
9644 uint32 maxHealth
= GetMaxHealth();
9648 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9651 if(GetTypeId() == TYPEID_PLAYER
)
9653 if(((Player
*)this)->GetGroup())
9654 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9656 else if(((Creature
*)this)->isPet())
9658 Pet
*pet
= ((Pet
*)this);
9659 if(pet
->isControlled())
9661 Unit
*owner
= GetOwner();
9662 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9663 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9668 void Unit::SetMaxHealth(uint32 val
)
9670 uint32 health
= GetHealth();
9671 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9674 if(GetTypeId() == TYPEID_PLAYER
)
9676 if(((Player
*)this)->GetGroup())
9677 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9679 else if(((Creature
*)this)->isPet())
9681 Pet
*pet
= ((Pet
*)this);
9682 if(pet
->isControlled())
9684 Unit
*owner
= GetOwner();
9685 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9686 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9694 void Unit::SetPower(Powers power
, uint32 val
)
9696 uint32 maxPower
= GetMaxPower(power
);
9700 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9702 WorldPacket
data(SMSG_POWER_UPDATE
);
9703 data
.append(GetPackGUID());
9704 data
<< uint8(power
);
9705 data
<< uint32(val
);
9706 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9709 if(GetTypeId() == TYPEID_PLAYER
)
9711 if(((Player
*)this)->GetGroup())
9712 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9714 else if(((Creature
*)this)->isPet())
9716 Pet
*pet
= ((Pet
*)this);
9717 if(pet
->isControlled())
9719 Unit
*owner
= GetOwner();
9720 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9721 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9724 // Update the pet's character sheet with happiness damage bonus
9725 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9727 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9732 void Unit::SetMaxPower(Powers power
, uint32 val
)
9734 uint32 cur_power
= GetPower(power
);
9735 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9738 if(GetTypeId() == TYPEID_PLAYER
)
9740 if(((Player
*)this)->GetGroup())
9741 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9743 else if(((Creature
*)this)->isPet())
9745 Pet
*pet
= ((Pet
*)this);
9746 if(pet
->isControlled())
9748 Unit
*owner
= GetOwner();
9749 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9750 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9755 SetPower(power
, val
);
9758 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9760 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9763 if(GetTypeId() == TYPEID_PLAYER
)
9765 if(((Player
*)this)->GetGroup())
9766 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9768 else if(((Creature
*)this)->isPet())
9770 Pet
*pet
= ((Pet
*)this);
9771 if(pet
->isControlled())
9773 Unit
*owner
= GetOwner();
9774 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9775 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9780 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9782 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9785 if(GetTypeId() == TYPEID_PLAYER
)
9787 if(((Player
*)this)->GetGroup())
9788 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9790 else if(((Creature
*)this)->isPet())
9792 Pet
*pet
= ((Pet
*)this);
9793 if(pet
->isControlled())
9795 Unit
*owner
= GetOwner();
9796 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9797 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9802 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9804 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9806 tAuraProcTriggerDamage
.push_back(aura
);
9808 tAuraProcTriggerDamage
.remove(aura
);
9811 uint32
Unit::GetCreatePowers( Powers power
) const
9813 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9816 case POWER_MANA
: return GetCreateMana();
9817 case POWER_RAGE
: return 1000;
9818 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9819 case POWER_ENERGY
: return 100;
9820 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9821 case POWER_RUNIC_POWER
: return 1000;
9827 void Unit::AddToWorld()
9829 Object::AddToWorld();
9832 void Unit::RemoveFromWorld()
9837 RemoveNotOwnSingleTargetAuras();
9840 Object::RemoveFromWorld();
9843 void Unit::CleanupsBeforeDelete()
9845 if(m_uint32Values
) // only for fully created object
9847 InterruptNonMeleeSpells(true);
9848 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted ans will deleated at call in Map::RemoveAllObjectsInRemoveList
9850 ClearComboPointHolders();
9852 getHostilRefManager().setOnlineOfflineState(false);
9854 RemoveAllGameObjects();
9855 RemoveAllDynObjects();
9856 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9861 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9864 m_charmInfo
= new CharmInfo(charm
);
9868 CharmInfo::CharmInfo(Unit
* unit
)
9869 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9871 for(int i
=0; i
<4; ++i
)
9873 m_charmspells
[i
].spellId
= 0;
9874 m_charmspells
[i
].active
= ACT_DISABLED
;
9878 void CharmInfo::InitPetActionBar()
9880 // the first 3 SpellOrActions are attack, follow and stay
9881 for(uint32 i
= 0; i
< 3; i
++)
9883 PetActionBar
[i
].Type
= ACT_COMMAND
;
9884 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9886 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9887 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9889 for(uint32 i
=0; i
< 4; i
++)
9891 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9892 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9896 void CharmInfo::InitEmptyActionBar()
9898 for(uint32 x
= 1; x
< 10; ++x
)
9900 PetActionBar
[x
].Type
= ACT_CAST
;
9901 PetActionBar
[x
].SpellOrAction
= 0;
9903 PetActionBar
[0].Type
= ACT_COMMAND
;
9904 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9907 void CharmInfo::InitPossessCreateSpells()
9909 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9912 InitEmptyActionBar(); //charm action bar
9914 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9916 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9917 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9919 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9923 void CharmInfo::InitCharmCreateSpells()
9925 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9927 InitEmptyActionBar();
9933 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9935 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9936 m_charmspells
[x
].spellId
= spellId
;
9941 if (IsPassiveSpell(spellId
))
9943 m_unit
->CastSpell(m_unit
, spellId
, true);
9944 m_charmspells
[x
].active
= ACT_PASSIVE
;
9948 ActiveStates newstate
;
9949 bool onlyselfcast
= true;
9950 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9952 if(!spellInfo
) onlyselfcast
= false;
9953 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9955 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9956 onlyselfcast
= false;
9959 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9960 newstate
= ACT_DISABLED
;
9962 newstate
= ACT_CAST
;
9964 AddSpellToAB(0, spellId
, newstate
);
9969 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9971 for(uint8 i
= 0; i
< 10; i
++)
9973 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9975 PetActionBar
[i
].SpellOrAction
= newid
;
9978 if(newstate
== ACT_DECIDE
)
9979 PetActionBar
[i
].Type
= ACT_DISABLED
;
9981 PetActionBar
[i
].Type
= newstate
;
9990 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9992 if(IsPassiveSpell(spellid
))
9995 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9997 if(spellid
== m_charmspells
[x
].spellId
)
9999 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
10004 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10006 m_petnumber
= petnumber
;
10008 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10010 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10013 bool Unit::isFrozen() const
10015 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10016 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10017 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10022 struct ProcTriggeredData
10024 ProcTriggeredData(SpellEntry
const * _spellInfo
, uint32 _spellParam
, Aura
* _triggeredByAura
, uint32 _cooldown
)
10025 : spellInfo(_spellInfo
), spellParam(_spellParam
), triggeredByAura(_triggeredByAura
),
10026 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10027 cooldown(_cooldown
)
10030 SpellEntry
const * spellInfo
;
10032 Aura
* triggeredByAura
;
10033 Unit::spellEffectPair triggeredByAura_SpellPair
;
10037 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10039 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10041 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10043 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10044 ProcTriggeredList procTriggered
;
10046 AuraList
const& auras
= GetAurasByType(*aur
);
10047 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10051 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
10055 SpellProcEventEntry
const *spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10056 if(!spellProcEvent
)
10058 // used to prevent spam in log about same non-handled spells
10059 static std::set
<uint32
> nonHandledSpellProcSet
;
10061 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10063 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10064 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10067 // spell.dbc use totally different flags, that only can create problems if used.
10071 // Check spellProcEvent data requirements
10072 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10075 // Check if current equipment allows aura to proc
10076 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10078 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10080 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10082 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10085 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10087 // Check if player is wearing shield
10088 Item
*item
= ((Player
*)this)->GetShield(true);
10089 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10094 float chance
= (float)spellProto
->procChance
;
10096 if(Player
* modOwner
= GetSpellModOwner())
10097 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10099 if(!isVictim
&& spellProcEvent
->ppmRate
!= 0)
10101 uint32 WeaponSpeed
= GetAttackTime(attType
);
10102 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10105 if(roll_chance_f(chance
))
10107 uint32 cooldown
= spellProcEvent
->cooldown
;
10109 uint32 i_spell_eff
= (*i
)->GetEffIndex();
10111 int32 i_spell_param
;
10114 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10115 i_spell_param
= procFlag
;
10117 case SPELL_AURA_DUMMY
:
10118 case SPELL_AURA_PRAYER_OF_MENDING
:
10119 case SPELL_AURA_MOD_HASTE
:
10120 i_spell_param
= i_spell_eff
;
10122 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10123 i_spell_param
= (*i
)->GetModifier()->m_miscvalue
;
10126 i_spell_param
= (*i
)->GetModifier()->m_amount
;
10130 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
, cooldown
) );
10134 // Handle effects proceed this time
10135 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10137 // Some auras can be deleted in function called in this loop (except first, ofc)
10138 // Until storing auras in std::multimap to hard check deleting by another way
10139 if(i
!= procTriggered
.begin())
10141 bool found
= false;
10142 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10143 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10144 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10146 if(itr
->second
==i
->triggeredByAura
)
10155 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
);
10156 sLog
.outError("It can be deleted one from early proccesed auras:");
10157 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10158 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10159 sLog
.outError(" <end of list>");
10164 // save charges existence before processing to prevent crash at access to deleted triggered aura after
10165 bool triggeredByAuraWithCharges
= i
->triggeredByAura
->m_procCharges
> 0;
10167 bool casted
= false;
10170 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10172 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10173 casted
= HandleProcTriggerSpell(pTarget
, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
,attType
,i
->cooldown
);
10176 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10178 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i
->spellParam
, i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10179 uint32 damage
= i
->spellParam
;
10180 SpellNonMeleeDamageLog(pTarget
, i
->spellInfo
->Id
, damage
, true, true);
10184 case SPELL_AURA_DUMMY
:
10186 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10187 casted
= HandleDummyAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10190 case SPELL_AURA_PRAYER_OF_MENDING
:
10192 sLog
.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10194 // aura can be deleted at casts
10195 int32 heal
= i
->triggeredByAura
->GetModifier()->m_amount
;
10196 uint64 caster_guid
= i
->triggeredByAura
->GetCasterGUID();
10199 int32 jumps
= i
->triggeredByAura
->m_procCharges
-1;
10201 // current aura expire
10202 i
->triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10204 // next target selection
10205 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10207 Aura
* aura
= i
->triggeredByAura
;
10209 SpellEntry
const* spellProto
= aura
->GetSpellProto();
10210 uint32 effIdx
= aura
->GetEffIndex();
10213 if (spellProto
->EffectRadiusIndex
[effIdx
])
10214 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10216 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10218 if(Player
* caster
= ((Player
*)aura
->GetCaster()))
10220 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10222 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10224 // aura will applied from caster, but spell casted from current aura holder
10225 SpellModifier
*mod
= new SpellModifier
;
10226 mod
->op
= SPELLMOD_CHARGES
;
10227 mod
->value
= jumps
-5; // negative
10228 mod
->type
= SPELLMOD_FLAT
;
10229 mod
->spellId
= spellProto
->Id
;
10230 mod
->effectId
= effIdx
;
10231 mod
->lastAffected
= NULL
;
10232 mod
->mask
= spellProto
->SpellFamilyFlags
;
10235 caster
->AddSpellMod(mod
, true);
10236 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,aura
,caster
->GetGUID());
10237 caster
->AddSpellMod(mod
, false);
10243 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10247 case SPELL_AURA_MOD_HASTE
:
10249 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10250 casted
= HandleHasteAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10253 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10255 // nothing do, just charges counter
10256 // but count only in case appropriate school damage
10257 casted
= i
->triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10260 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10262 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10263 casted
= HandleOverrideClassScriptAuraProc(pTarget
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
,i
->cooldown
);
10268 // nothing do, just charges counter
10274 // Update charge (aura can be removed by triggers)
10275 if(casted
&& triggeredByAuraWithCharges
)
10277 // need found aura (can be dropped by triggers)
10278 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10279 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10280 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10282 if(itr
->second
== i
->triggeredByAura
)
10284 if(i
->triggeredByAura
->m_procCharges
> 0)
10285 i
->triggeredByAura
->m_procCharges
-= 1;
10287 i
->triggeredByAura
->UpdateAuraCharges();
10294 // Safely remove auras with zero charges
10295 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10298 if((*i
)->m_procCharges
== 0)
10300 RemoveAurasDueToSpell((*i
)->GetId());
10301 next
= auras
.begin();
10307 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10309 return SPELL_SCHOOL_MASK_NORMAL
;
10312 Player
* Unit::GetSpellModOwner()
10314 if(GetTypeId()==TYPEID_PLAYER
)
10315 return (Player
*)this;
10316 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10318 Unit
* owner
= GetOwner();
10319 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10320 return (Player
*)owner
;
10325 ///----------Pet responses methods-----------------
10326 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10328 Unit
*owner
= GetCharmerOrOwner();
10329 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10332 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10333 data
<< uint8(0); // cast count?
10334 data
<< uint32(spellid
);
10335 data
<< uint8(msg
);
10336 // uint32 for some reason
10337 // uint32 for some reason
10338 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10341 void Unit::SendPetActionFeedback (uint8 msg
)
10343 Unit
* owner
= GetOwner();
10344 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10347 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10348 data
<< uint8(msg
);
10349 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10352 void Unit::SendPetTalk (uint32 pettalk
)
10354 Unit
* owner
= GetOwner();
10355 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10358 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10359 data
<< uint64(GetGUID());
10360 data
<< uint32(pettalk
);
10361 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10364 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10366 Unit
* owner
= GetOwner();
10367 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10370 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10371 data
<< uint64(GetGUID());
10372 data
<< uint8(0x0); // flags (0x1, 0x2)
10373 data
<< uint32(spellid
);
10374 data
<< uint32(cooltime
);
10376 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10379 void Unit::SendPetClearCooldown (uint32 spellid
)
10381 Unit
* owner
= GetOwner();
10382 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10385 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10386 data
<< uint32(spellid
);
10387 data
<< uint64(GetGUID());
10388 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10391 void Unit::SendPetAIReaction(uint64 guid
)
10393 Unit
* owner
= GetOwner();
10394 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10397 WorldPacket
data(SMSG_AI_REACTION
, 12);
10398 data
<< uint64(guid
) << uint32(00000002);
10399 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10402 ///----------End of Pet responses methods----------
10404 void Unit::StopMoving()
10406 clearUnitState(UNIT_STAT_MOVING
);
10408 // send explicit stop packet
10409 // rely on vmaps here because for exemple stormwind is in air
10410 float z
= MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10411 //if (fabs(GetPositionZ() - z) < 2.0f)
10412 // Relocate(GetPositionX(), GetPositionY(), z);
10413 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10415 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10417 // update position and orientation;
10419 BuildHeartBeatMsg(&data
);
10420 SendMessageToSet(&data
,false);
10423 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10427 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10430 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10432 GetMotionMaster()->MovementExpired(false);
10433 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10435 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10437 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10441 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10443 GetMotionMaster()->MovementExpired(false);
10445 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10447 // restore appropriate movement generator
10449 GetMotionMaster()->MoveChase(getVictim());
10451 GetMotionMaster()->Initialize();
10453 // attack caster if can
10454 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10455 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10456 ((Creature
*)this)->AI()->AttackStart(caster
);
10460 if (GetTypeId() == TYPEID_PLAYER
)
10461 ((Player
*)this)->SetClientControl(this, !apply
);
10464 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10468 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10470 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10472 GetMotionMaster()->MoveConfused();
10476 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10478 GetMotionMaster()->MovementExpired(false);
10480 if (GetTypeId() == TYPEID_UNIT
)
10482 // if in combat restore movement generator
10484 GetMotionMaster()->MoveChase(getVictim());
10488 if(GetTypeId() == TYPEID_PLAYER
)
10489 ((Player
*)this)->SetClientControl(this, !apply
);
10492 bool Unit::IsSitState() const
10494 uint8 s
= getStandState();
10495 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10496 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10497 s
== PLAYER_STATE_SIT
;
10500 bool Unit::IsStandState() const
10502 uint8 s
= getStandState();
10503 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10506 void Unit::SetStandState(uint8 state
)
10508 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10510 if (IsStandState())
10511 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10513 if(GetTypeId()==TYPEID_PLAYER
)
10515 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10516 data
<< (uint8
)state
;
10517 ((Player
*)this)->GetSession()->SendPacket(&data
);
10521 bool Unit::IsPolymorphed() const
10523 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10526 void Unit::SetDisplayId(uint32 modelId
)
10528 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10530 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10532 Pet
*pet
= ((Pet
*)this);
10533 if(!pet
->isControlled())
10535 Unit
*owner
= GetOwner();
10536 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10537 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10541 void Unit::ClearComboPointHolders()
10543 while(!m_ComboPointHolders
.empty())
10545 uint32 lowguid
= *m_ComboPointHolders
.begin();
10547 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10548 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10549 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10551 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10555 void Unit::ClearAllReactives()
10558 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10559 m_reactiveTimer
[i
] = 0;
10561 if (HasAuraState( AURA_STATE_DEFENSE
))
10562 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10563 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10564 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10565 if (HasAuraState( AURA_STATE_CRIT
))
10566 ModifyAuraState(AURA_STATE_CRIT
, false);
10567 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10568 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10570 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10571 ((Player
*)this)->ClearComboPoints();
10574 void Unit::UpdateReactives( uint32 p_time
)
10576 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10578 ReactiveType reactive
= ReactiveType(i
);
10580 if(!m_reactiveTimer
[reactive
])
10583 if ( m_reactiveTimer
[reactive
] <= p_time
)
10585 m_reactiveTimer
[reactive
] = 0;
10587 switch ( reactive
)
10589 case REACTIVE_DEFENSE
:
10590 if (HasAuraState(AURA_STATE_DEFENSE
))
10591 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10593 case REACTIVE_HUNTER_PARRY
:
10594 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10595 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10597 case REACTIVE_CRIT
:
10598 if (HasAuraState(AURA_STATE_CRIT
))
10599 ModifyAuraState(AURA_STATE_CRIT
, false);
10601 case REACTIVE_HUNTER_CRIT
:
10602 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10603 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10605 case REACTIVE_OVERPOWER
:
10606 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10607 ((Player
*)this)->ClearComboPoints();
10615 m_reactiveTimer
[reactive
] -= p_time
;
10620 Unit
* Unit::SelectNearbyTarget() const
10622 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10624 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10625 cell
.SetNoCreate();
10627 std::list
<Unit
*> targets
;
10630 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10631 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10633 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10634 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10636 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10637 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10638 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10641 // remove current target
10643 targets
.remove(getVictim());
10645 // remove not LoS targets
10646 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10648 if(!IsWithinLOSInMap(*tIter
))
10650 std::list
<Unit
*>::iterator tIter2
= tIter
;
10652 targets
.erase(tIter2
);
10658 // no appropriate targets
10659 if(targets
.empty())
10663 uint32 rIdx
= urand(0,targets
.size()-1);
10664 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10665 for(uint32 i
= 0; i
< rIdx
; ++i
)
10671 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10675 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10676 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10680 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10681 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10685 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10688 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10690 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10693 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10695 if (CastingTime
> 7000) CastingTime
= 7000;
10696 if (CastingTime
< 1500) CastingTime
= 1500;
10698 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10699 CastingTime
= 3500;
10701 int32 overTime
= 0;
10703 bool DirectDamage
= false;
10704 bool AreaEffect
= false;
10706 for ( uint32 i
=0; i
<3;i
++)
10708 switch ( spellProto
->Effect
[i
] )
10710 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10711 case SPELL_EFFECT_POWER_DRAIN
:
10712 case SPELL_EFFECT_HEALTH_LEECH
:
10713 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10714 case SPELL_EFFECT_POWER_BURN
:
10715 case SPELL_EFFECT_HEAL
:
10716 DirectDamage
= true;
10718 case SPELL_EFFECT_APPLY_AURA
:
10719 switch ( spellProto
->EffectApplyAuraName
[i
] )
10721 case SPELL_AURA_PERIODIC_DAMAGE
:
10722 case SPELL_AURA_PERIODIC_HEAL
:
10723 case SPELL_AURA_PERIODIC_LEECH
:
10724 if ( GetSpellDuration(spellProto
) )
10725 overTime
= GetSpellDuration(spellProto
);
10728 // -5% per additional effect
10736 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10740 // Combined Spells with Both Over Time and Direct Damage
10741 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10743 // mainly for DoTs which are 3500 here otherwise
10744 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10745 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10746 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10747 // Portion to Over Time
10748 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10750 if ( damagetype
== DOT
)
10751 CastingTime
= uint32(CastingTime
* PtOT
);
10752 else if ( PtOT
< 1.0f
)
10753 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10758 // Area Effect Spells receive only half of bonus
10762 // -5% of total per any additional effect
10763 for ( uint8 i
=0; i
<effects
; ++i
)
10765 if ( CastingTime
> 175 )
10767 CastingTime
-= 175;
10776 return CastingTime
;
10779 void Unit::UpdateAuraForGroup(uint8 slot
)
10781 if(GetTypeId() == TYPEID_PLAYER
)
10783 Player
* player
= (Player
*)this;
10784 if(player
->GetGroup())
10786 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10787 player
->SetAuraUpdateMask(slot
);
10790 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10792 Pet
*pet
= ((Pet
*)this);
10793 if(pet
->isControlled())
10795 Unit
*owner
= GetOwner();
10796 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10798 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10799 pet
->SetAuraUpdateMask(slot
);
10805 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10807 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10808 return float(GetAttackTime(attType
))/1000.0f
;
10810 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10812 return 2.4; // fist attack
10814 switch (Weapon
->GetProto()->InventoryType
)
10816 case INVTYPE_2HWEAPON
:
10818 case INVTYPE_RANGED
:
10819 case INVTYPE_RANGEDRIGHT
:
10820 case INVTYPE_THROWN
:
10822 case INVTYPE_WEAPON
:
10823 case INVTYPE_WEAPONMAINHAND
:
10824 case INVTYPE_WEAPONOFFHAND
:
10826 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10830 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10832 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10833 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10834 if ((*itr
)->GetId() == spell_id
)
10840 bool Unit::IsUnderLastManaUseEffect() const
10842 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10845 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10847 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10849 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10852 player
->SetContestedPvPTimer(30000);
10853 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10855 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10856 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10857 // call MoveInLineOfSight for nearby contested guards
10858 SetVisibility(GetVisibility());
10860 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10862 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10863 // call MoveInLineOfSight for nearby contested guards
10864 SetVisibility(GetVisibility());
10868 void Unit::AddPetAura(PetAura
const* petSpell
)
10870 m_petAuras
.insert(petSpell
);
10871 if(Pet
* pet
= GetPet())
10872 pet
->CastPetAura(petSpell
);
10875 void Unit::RemovePetAura(PetAura
const* petSpell
)
10877 m_petAuras
.erase(petSpell
);
10878 if(Pet
* pet
= GetPet())
10879 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10882 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10884 Pet
* pet
= new Pet(HUNTER_PET
);
10886 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10892 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, this->GetGUID());
10893 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, this->GetGUID());
10894 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,this->getFaction());
10895 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10897 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10898 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10900 if(!pet
->InitStatsForLevel(level
))
10902 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10907 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10908 // this enables pet details window (Shift+P)
10909 pet
->AIM_Initialize();
10910 pet
->InitPetCreateSpells();
10911 pet
->SetHealth(pet
->GetMaxHealth());