2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
49 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
53 1.25f
, // MOVE_WALKBACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIMBACK
56 3.141594f
, // MOVE_TURN
61 // auraTypes contains attacker auras capable of proc'ing cast auras
62 static Unit::AuraTypeSet
GenerateAttakerProcCastAuraTypes()
64 static Unit::AuraTypeSet auraTypes
;
65 auraTypes
.insert(SPELL_AURA_DUMMY
);
66 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
67 auraTypes
.insert(SPELL_AURA_MOD_HASTE
);
68 auraTypes
.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
72 // auraTypes contains victim auras capable of proc'ing cast auras
73 static Unit::AuraTypeSet
GenerateVictimProcCastAuraTypes()
75 static Unit::AuraTypeSet auraTypes
;
76 auraTypes
.insert(SPELL_AURA_DUMMY
);
77 auraTypes
.insert(SPELL_AURA_PRAYER_OF_MENDING
);
78 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
82 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
83 static Unit::AuraTypeSet
GenerateAttakerProcEffectAuraTypes()
85 static Unit::AuraTypeSet auraTypes
;
86 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_DONE
);
87 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
88 auraTypes
.insert(SPELL_AURA_MOD_CASTING_SPEED
);
89 auraTypes
.insert(SPELL_AURA_MOD_RATING
);
93 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
94 static Unit::AuraTypeSet
GenerateVictimProcEffectAuraTypes()
96 static Unit::AuraTypeSet auraTypes
;
97 auraTypes
.insert(SPELL_AURA_MOD_RESISTANCE
);
98 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
99 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
100 auraTypes
.insert(SPELL_AURA_MOD_BLOCK_PERCENT
);
101 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
105 static Unit::AuraTypeSet attackerProcCastAuraTypes
= GenerateAttakerProcCastAuraTypes();
106 static Unit::AuraTypeSet attackerProcEffectAuraTypes
= GenerateAttakerProcEffectAuraTypes();
108 static Unit::AuraTypeSet victimProcCastAuraTypes
= GenerateVictimProcCastAuraTypes();
109 static Unit::AuraTypeSet victimProcEffectAuraTypes
= GenerateVictimProcEffectAuraTypes();
111 // auraTypes contains auras capable of proc'ing for attacker and victim
112 static Unit::AuraTypeSet
GenerateProcAuraTypes()
114 Unit::AuraTypeSet auraTypes
;
115 auraTypes
.insert(attackerProcCastAuraTypes
.begin(),attackerProcCastAuraTypes
.end());
116 auraTypes
.insert(attackerProcEffectAuraTypes
.begin(),attackerProcEffectAuraTypes
.end());
117 auraTypes
.insert(victimProcCastAuraTypes
.begin(),victimProcCastAuraTypes
.end());
118 auraTypes
.insert(victimProcEffectAuraTypes
.begin(),victimProcEffectAuraTypes
.end());
122 static Unit::AuraTypeSet procAuraTypes
= GenerateProcAuraTypes();
124 bool IsPassiveStackableSpell( uint32 spellId
)
126 if(!IsPassiveSpell(spellId
))
129 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
133 for(int j
= 0; j
< 3; ++j
)
135 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
143 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
145 m_objectType
|= TYPEMASK_UNIT
;
146 m_objectTypeId
= TYPEID_UNIT
;
148 m_updateFlag
= (UPDATEFLAG_HIGHGUID
| UPDATEFLAG_LIVING
| UPDATEFLAG_HASPOSITION
);
150 m_attackTimer
[BASE_ATTACK
] = 0;
151 m_attackTimer
[OFF_ATTACK
] = 0;
152 m_attackTimer
[RANGED_ATTACK
] = 0;
153 m_modAttackSpeedPct
[BASE_ATTACK
] = 1.0f
;
154 m_modAttackSpeedPct
[OFF_ATTACK
] = 1.0f
;
155 m_modAttackSpeedPct
[RANGED_ATTACK
] = 1.0f
;
161 m_deathState
= ALIVE
;
163 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
164 m_currentSpells
[i
] = NULL
;
168 for(int i
= 0; i
< MAX_TOTEM
; ++i
)
171 m_ObjectSlot
[0] = m_ObjectSlot
[1] = m_ObjectSlot
[2] = m_ObjectSlot
[3] = 0;
173 //m_AurasCheck = 2000;
174 //m_removeAuraTimer = 4;
178 m_Visibility
= VISIBILITY_ON
;
180 m_detectInvisibilityMask
= 0;
181 m_invisibilityMask
= 0;
183 m_ShapeShiftFormSpellId
= 0;
184 m_canModifyStats
= false;
186 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
187 m_spellImmune
[i
].clear();
188 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
190 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
191 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
192 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
193 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
195 // implement 50% base damage from offhand
196 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
198 for (int i
= 0; i
< 3; i
++)
200 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
201 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
203 for (int i
= 0; i
< MAX_STATS
; i
++)
204 m_createStats
[i
] = 0.0f
;
207 m_modMeleeHitChance
= 0.0f
;
208 m_modRangedHitChance
= 0.0f
;
209 m_modSpellHitChance
= 0.0f
;
210 m_baseSpellCritChance
= 5;
215 //m_victimThreat = 0.0f;
216 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
217 m_threatModifier
[i
] = 1.0f
;
219 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
220 m_speed_rate
[i
] = 1.0f
;
224 m_unit_movement_flags
= 0;
226 // remove aurastates allowing special moves
227 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
228 m_reactiveTimer
[i
] = 0;
233 // set current spells as deletable
234 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
236 if (m_currentSpells
[i
])
238 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
239 m_currentSpells
[i
] = NULL
;
243 RemoveAllGameObjects();
244 RemoveAllDynObjects();
246 if(m_charmInfo
) delete m_charmInfo
;
249 void Unit::Update( uint32 p_time
)
251 /*if(p_time > m_AurasCheck)
256 m_AurasCheck -= p_time;*/
258 // WARNING! Order of execution here is important, do not change.
259 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
260 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
261 m_Events
.Update( p_time
);
262 _UpdateSpells( p_time
);
264 // update combat timer only for players and pets
265 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
267 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
268 // targets without stopping half way there and running off.
269 // These flags are reset after target dies or another command is given.
270 if( m_HostilRefManager
.isEmpty() )
272 // m_CombatTimer set at aura start and it will be freeze until aura removing
273 if ( m_CombatTimer
<= p_time
)
276 m_CombatTimer
-= p_time
;
280 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
282 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
285 // update abilities available only for fraction of time
286 UpdateReactives( p_time
);
288 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, GetHealth() < GetMaxHealth()*0.20f
);
289 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, GetHealth() < GetMaxHealth()*0.35f
);
291 i_motionMaster
.UpdateMotion(p_time
);
294 bool Unit::haveOffhandWeapon() const
296 if(GetTypeId() == TYPEID_PLAYER
)
297 return ((Player
*)this)->GetWeaponForAttack(OFF_ATTACK
,true);
302 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player
* player
)
305 if(GetMotionMaster()->GetDestination(x
, y
, z
))
306 SendMonsterMoveWithSpeed(x
, y
, z
, GetUnitMovementFlags(), 0, player
);
309 void Unit::SendMonsterMoveWithSpeed(float x
, float y
, float z
, uint32 MovementFlags
, uint32 transitTime
, Player
* player
)
313 float dx
= x
- GetPositionX();
314 float dy
= y
- GetPositionY();
315 float dz
= z
- GetPositionZ();
317 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
323 double speed
= GetSpeed((MovementFlags
& MOVEMENTFLAG_WALK_MODE
) ? MOVE_WALK
: MOVE_RUN
);
327 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
329 //float orientation = (float)atan2((double)dy, (double)dx);
330 SendMonsterMove(x
, y
, z
, 0, MovementFlags
, transitTime
, player
);
333 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, uint32 MovementFlags
, uint32 Time
, Player
* player
)
335 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
336 data
.append(GetPackGUID());
338 // Point A, starting location
339 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
340 // unknown field - unrelated to orientation
341 // seems to increment about 1000 for every 1.7 seconds
342 // for now, we'll just use mstime
345 data
<< uint8(type
); // unknown
348 case 0: // normal packet
350 case 1: // stop packet
351 SendMessageToSet( &data
, true );
353 case 2: // not used currently
358 case 3: // not used currently
359 data
<< uint64(0); // probably target guid
361 case 4: // not used currently
362 data
<< float(0); // probably orientation
366 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
367 data
<< uint32(MovementFlags
);
369 data
<< Time
; // Time in between points
370 data
<< uint32(1); // 1 single waypoint
371 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
374 player
->GetSession()->SendPacket(&data
);
376 SendMessageToSet( &data
, true );
379 void Unit::SendMonsterMoveByPath(Path
const& path
, uint32 start
, uint32 end
, uint32 MovementFlags
)
381 uint32 traveltime
= uint32(path
.GetTotalLength(start
, end
) * 32);
383 uint32 pathSize
= end
-start
;
385 WorldPacket
data( SMSG_MONSTER_MOVE
, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize
*4*3) );
386 data
.append(GetPackGUID());
387 data
<< GetPositionX();
388 data
<< GetPositionY();
389 data
<< GetPositionZ();
391 // unknown field - unrelated to orientation
392 // seems to increment about 1000 for every 1.7 seconds
393 // for now, we'll just use mstime
397 data
<< uint32( MovementFlags
);
398 data
<< uint32( traveltime
);
399 data
<< uint32( pathSize
);
400 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
402 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
403 SendMessageToSet(&data
, true);
406 void Unit::resetAttackTimer(WeaponAttackType type
)
408 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
411 bool Unit::canReachWithAttack(Unit
*pVictim
) const
414 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
417 return IsWithinDistInMap(pVictim
, reach
);
420 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
422 if (auraType
>= TOTAL_AURAS
) return;
423 AuraList::iterator iter
, next
;
424 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
431 RemoveAurasDueToSpell((*iter
)->GetId());
432 if (!m_modAuras
[auraType
].empty())
433 next
= m_modAuras
[auraType
].begin();
440 bool Unit::HasAuraType(AuraType auraType
) const
442 return (!m_modAuras
[auraType
].empty());
445 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
446 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
448 if(!HasAuraType(auraType
))
451 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
452 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
453 float chance
= float(damage
) / max_dmg
* 100.0f
;
454 if (roll_chance_f(chance
))
455 RemoveSpellsCausingAura(auraType
);
458 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
460 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
463 //You don't lose health from damage taken from another player while in a sanctuary
464 //You still see it in the combat log though
465 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
467 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
468 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
472 // remove affects from victim (including from 0 damage and DoTs)
474 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
476 // remove affects from attacker at any non-DoT damage (including 0 damage)
477 if( damagetype
!= DOT
)
479 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
480 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
483 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
485 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
486 pVictim
->SetStandState(PLAYER_STATE_NONE
);
489 //Script Event damage Deal
490 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
491 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
492 //Script Event damage taken
493 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
494 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
498 // Rage from physical damage received .
499 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
500 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
505 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
506 // root type spells do not dispel the root effect
507 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
508 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
510 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
512 // no xp,health if type 8 /critters/
513 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
515 pVictim
->setDeathState(JUST_DIED
);
516 pVictim
->SetHealth(0);
518 // allow loot only if has loot_id in creature_template
519 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
520 if(cInfo
&& cInfo
->lootid
)
521 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
523 // some critters required for quests
524 if(GetTypeId() == TYPEID_PLAYER
)
525 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
530 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
531 ((Creature
*)pVictim
)->AI()->AttackStart(this);
534 DEBUG_LOG("DealDamageStart");
536 uint32 health
= pVictim
->GetHealth();
537 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
539 // duel ends when player has 1 or less hp
540 bool duel_hasEnded
= false;
541 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
543 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
544 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
547 duel_hasEnded
= true;
550 if(pVictim
!= this && damagetype
!= DOT
)
552 SetInCombatWith(pVictim
);
553 pVictim
->SetInCombatWith(this);
555 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
556 SetContestedPvP(attackedPlayer
);
559 // Rage from Damage made (only from direct weapon damage)
560 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
562 uint32 weaponSpeedHitFactor
;
564 switch(cleanDamage
->attackType
)
568 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
569 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
571 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
573 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
579 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
580 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
582 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
584 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
593 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
595 if(((Player
*)pVictim
)->InBattleGround())
597 Player
*killer
= ((Player
*)this);
598 if(killer
!= ((Player
*)pVictim
))
599 if(BattleGround
*bg
= killer
->GetBattleGround())
600 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
604 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
605 ((Creature
*)pVictim
)->SetLootRecipient(this);
606 if (health
<= damage
)
608 // battleground things
609 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
611 Player
*killed
= ((Player
*)pVictim
);
612 Player
*killer
= NULL
;
613 if(GetTypeId() == TYPEID_PLAYER
)
614 killer
= ((Player
*)this);
615 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
617 Unit
*owner
= GetOwner();
618 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
619 killer
= ((Player
*)owner
);
623 if(BattleGround
*bg
= killed
->GetBattleGround())
624 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
627 DEBUG_LOG("DealDamage: victim just died");
629 // find player: owner of controlled `this` or `this` itself maybe
630 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
632 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
633 player
= ((Creature
*)pVictim
)->GetLootRecipient();
634 // Reward player, his pets, and group/raid members
635 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
636 if(player
&& player
!=pVictim
)
637 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
638 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
640 DEBUG_LOG("DealDamageAttackStop");
643 pVictim
->CombatStop();
644 pVictim
->getHostilRefManager().deleteReferences();
646 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
648 // if talent known but not triggered (check priest class for speedup check)
649 Aura
* spiritOfRedemtionTalentReady
= NULL
;
650 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
651 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
653 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
654 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
656 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
658 spiritOfRedemtionTalentReady
= *itr
;
664 DEBUG_LOG("SET JUST_DIED");
665 if(!spiritOfRedemtionTalentReady
)
666 pVictim
->setDeathState(JUST_DIED
);
668 DEBUG_LOG("DealDamageHealth1");
670 if(spiritOfRedemtionTalentReady
)
672 // save value before aura remove
673 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
675 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
677 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
678 pVictim
->RemoveAllAurasOnDeath();
680 // restore for use at real death
681 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
683 // FORM_SPIRITOFREDEMPTION and related auras
684 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
687 pVictim
->SetHealth(0);
689 // remember victim PvP death for corpse type and corpse reclaim delay
690 // at original death (not at SpiritOfRedemtionTalent timeout)
691 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
692 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
694 // Call KilledUnit for creatures
695 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
696 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
698 // 10% durability loss on death
699 // clean InHateListOf
700 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
702 // only if not player and not controlled by player pet. And not at BG
703 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
705 DEBUG_LOG("We are dead, loosing 10 percents durability");
706 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
707 // durability lost message
708 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
709 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
712 else // creature died
714 DEBUG_LOG("DealDamageNotPlayer");
715 Creature
*cVictim
= (Creature
*)pVictim
;
717 if(!cVictim
->isPet())
719 cVictim
->DeleteThreatList();
720 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
722 // Call creature just died function
724 cVictim
->AI()->JustDied(this);
726 // Dungeon specific stuff, only applies to players killing creatures
727 if(cVictim
->GetInstanceId())
729 Map
*m
= cVictim
->GetMap();
730 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
731 // TODO: do instance binding anyway if the charmer/owner is offline
733 if(m
->IsDungeon() && creditedPlayer
)
735 if(m
->IsRaid() || m
->IsHeroic())
737 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
738 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
742 // the reset time is set but not added to the scheduler
743 // until the players leave the instance
744 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
745 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
746 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
752 // last damage from non duel opponent or opponent controlled creature
755 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
756 Player
*he
= (Player
*)pVictim
;
760 he
->duel
->opponent
->CombatStopWithPets(true);
761 he
->CombatStopWithPets(true);
763 he
->DuelComplete(DUEL_INTERUPTED
);
766 else // if (health <= damage)
768 DEBUG_LOG("DealDamageAlive");
770 pVictim
->ModifyHealth(- (int32
)damage
);
772 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
773 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
775 uint32 procVictim
= PROC_FLAG_NONE
;
777 // if just dropped below 20% (for CheatDeath)
778 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
779 procVictim
= PROC_FLAG_LOW_HEALTH
;
781 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
784 if(damagetype
!= DOT
)
788 // if have target and damage pVictim just call AI reaction
789 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
790 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
794 // if not have main target then attack state with target (including AI call)
795 //start melee attacks only after melee hit
796 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
800 // polymorphed and other negative transformed cases
801 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
802 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
804 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
805 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
807 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
809 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
810 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
812 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
814 else // victim is a player
816 // Rage from damage received
817 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
819 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
820 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
823 // random durability for items (HIT TAKEN)
824 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
826 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
827 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
831 if(GetTypeId()==TYPEID_PLAYER
)
833 // random durability for items (HIT DONE)
834 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
836 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
837 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
841 // TODO: Store auras by interrupt flag to speed this up.
842 AuraMap
& vAuras
= pVictim
->GetAuras();
843 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
845 const SpellEntry
*se
= i
->second
->GetSpellProto();
847 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
850 if (se
->procFlags
& (1<<3))
852 if (!roll_chance_i(se
->procChance
))
857 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
858 // FIXME: this may cause the auras with proc chance to be rerolled several times
859 next
= vAuras
.begin();
864 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
866 if( damagetype
!= DOT
)
868 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
870 // skip channeled spell (processed differently below)
871 if (i
== CURRENT_CHANNELED_SPELL
)
874 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
875 if(spell
->getState() == SPELL_STATE_PREPARING
)
880 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
882 if (spell
->getState() == SPELL_STATE_CASTING
)
884 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
885 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
887 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
888 spell
->DelayedChannel();
890 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
892 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
893 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
896 else if (spell
->getState() == SPELL_STATE_DELAYED
)
897 // break channeled spell in delayed state on damage
899 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
900 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
905 // last damage from duel opponent
908 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
909 Player
*he
= (Player
*)pVictim
;
915 he
->duel
->opponent
->CombatStopWithPets(true);
916 he
->CombatStopWithPets(true);
918 he
->CastSpell(he
, 7267, true); // beg
919 he
->DuelComplete(DUEL_WON
);
923 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
928 void Unit::CastStop(uint32 except_spellid
)
930 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
931 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
932 InterruptSpell(i
,false);
935 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
937 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
941 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
945 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
948 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
952 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
957 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
959 if(!originalCaster
&& triggeredByAura
)
960 originalCaster
= triggeredByAura
->GetCasterGUID();
962 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
964 SpellCastTargets targets
;
965 targets
.setUnitTarget( Victim
);
966 spell
->m_CastItem
= castItem
;
967 spell
->prepare(&targets
, triggeredByAura
);
970 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
972 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
976 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
980 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggeredByAura
, originalCaster
);
983 void Unit::CastCustomSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
987 sLog
.outError("CastCustomSpell: unknown spell");
992 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
994 if(!originalCaster
&& triggeredByAura
)
995 originalCaster
= triggeredByAura
->GetCasterGUID();
997 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1000 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
1003 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1006 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1008 SpellCastTargets targets
;
1009 targets
.setUnitTarget( Victim
);
1010 spell
->m_CastItem
= castItem
;
1011 spell
->prepare(&targets
, triggeredByAura
);
1014 // used for scripting
1015 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1017 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1021 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()));
1025 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
1028 // used for scripting
1029 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1033 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1038 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1040 if(!originalCaster
&& triggeredByAura
)
1041 originalCaster
= triggeredByAura
->GetCasterGUID();
1043 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1045 SpellCastTargets targets
;
1046 targets
.setDestination(x
, y
, z
);
1047 spell
->m_CastItem
= castItem
;
1048 spell
->prepare(&targets
, triggeredByAura
);
1051 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1053 // TODO this in only generic way, check for exceptions
1054 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1056 // Per-damage class calculation
1057 switch (spellInfo
->DmgClass
)
1059 // Melee and Ranged Spells
1060 case SPELL_DAMAGE_CLASS_RANGED
:
1061 case SPELL_DAMAGE_CLASS_MELEE
:
1063 // Calculate physical outcome
1064 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1066 //Used to store the Hit Outcome
1067 cleanDamage
->hitOutCome
= outcome
;
1069 // Return miss/evade first (sends miss message)
1072 case MELEE_HIT_EVADE
:
1074 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1078 case MELEE_HIT_MISS
:
1080 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1083 if(GetTypeId()== TYPEID_PLAYER
)
1084 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1086 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1091 // Hitinfo, Victimstate
1092 uint32 hitInfo
= HITINFO_NORMALSWING
;
1093 VictimState victimState
= VICTIMSTATE_NORMAL
;
1096 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1098 // apply spellmod to Done damage
1099 if(Player
* modOwner
= GetSpellModOwner())
1100 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1102 //Calculate armor mitigation
1103 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1105 // random durability for main hand weapon (ABSORB)
1106 if(damageAfterArmor
< *damage
)
1107 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1108 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1109 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1111 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1112 *damage
= damageAfterArmor
;
1117 // Calculate damage bonus
1118 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1124 case MELEE_HIT_BLOCK_CRIT
:
1125 case MELEE_HIT_CRIT
:
1127 uint32 bonusDmg
= *damage
;
1129 // Apply crit_damage bonus
1130 if(Player
* modOwner
= GetSpellModOwner())
1131 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1133 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1134 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1135 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1136 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1137 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1139 *damage
+= bonusDmg
;
1141 // Resilience - reduce crit damage
1142 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1144 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1145 cleanDamage
->damage
+= resilienceReduction
;
1146 *damage
-= resilienceReduction
;
1150 hitInfo
|= HITINFO_CRITICALHIT
;
1152 ModifyAuraState(AURA_STATE_CRIT
, true);
1153 StartReactiveTimer( REACTIVE_CRIT
);
1155 if(getClass()==CLASS_HUNTER
)
1157 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1158 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1161 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1163 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1164 if (blocked_amount
>= *damage
)
1166 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1167 victimState
= VICTIMSTATE_BLOCKS
;
1168 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1173 // To Help Calculate Rage
1174 cleanDamage
->damage
+= blocked_amount
;
1175 *damage
= *damage
- blocked_amount
;
1178 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1179 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1181 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1184 ((Player
*)pVictim
)->UpdateDefense();
1186 // random durability for main hand weapon (BLOCK)
1187 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1188 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1193 case MELEE_HIT_PARRY
:
1195 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1197 victimState
= VICTIMSTATE_PARRY
;
1199 // Counter-attack ( explained in Unit::DoAttackDamage() )
1200 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1202 // Get attack timers
1203 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1204 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1206 // Reduce attack time
1207 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1209 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1210 float percent60
= 3 * percent20
;
1211 if(offtime
> percent20
&& offtime
<= percent60
)
1213 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1215 else if(offtime
> percent60
)
1217 offtime
-= 2 * percent20
;
1218 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1223 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1224 float percent60
= 3 * percent20
;
1225 if(basetime
> percent20
&& basetime
<= percent60
)
1227 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1229 else if(basetime
> percent60
)
1231 basetime
-= 2 * percent20
;
1232 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1237 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1239 // Update victim defense ?
1240 ((Player
*)pVictim
)->UpdateDefense();
1242 // random durability for main hand weapon (PARRY)
1243 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1244 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1248 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1250 // Mongoose bite - set only Counterattack here
1251 if (pVictim
->getClass() == CLASS_HUNTER
)
1253 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1254 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1258 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1259 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1263 case MELEE_HIT_DODGE
:
1265 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1266 ((Player
*)pVictim
)->UpdateDefense();
1268 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1270 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1271 victimState
= VICTIMSTATE_DODGE
;
1274 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1277 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1279 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1280 StartReactiveTimer( REACTIVE_OVERPOWER
);
1284 if (pVictim
->getClass() != CLASS_ROGUE
)
1286 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1287 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1291 case MELEE_HIT_BLOCK
:
1293 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1294 if (blocked_amount
>= *damage
)
1296 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1297 victimState
= VICTIMSTATE_BLOCKS
;
1298 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1303 // To Help Calculate Rage
1304 cleanDamage
->damage
+= blocked_amount
;
1305 *damage
= *damage
- blocked_amount
;
1308 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1309 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1311 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1314 ((Player
*)pVictim
)->UpdateDefense();
1316 // random durability for main hand weapon (BLOCK)
1317 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1318 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1322 case MELEE_HIT_EVADE
: // already processed early
1323 case MELEE_HIT_MISS
: // already processed early
1324 case MELEE_HIT_GLANCING
:
1325 case MELEE_HIT_CRUSHING
:
1326 case MELEE_HIT_NORMAL
:
1330 // do all damage=0 cases here
1332 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1337 case SPELL_DAMAGE_CLASS_NONE
:
1338 case SPELL_DAMAGE_CLASS_MAGIC
:
1340 // Calculate damage bonus
1341 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1343 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1346 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1348 // Resilience - reduce crit damage
1349 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1351 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1352 if(*damage
> damage_reduction
)
1353 *damage
-= damage_reduction
;
1358 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1360 // spell proc all magic damage==0 case in this function
1364 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1365 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1367 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1374 // TODO this in only generic way, check for exceptions
1375 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1378 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1380 if(!this || !pVictim
)
1382 if(!isAlive() || !pVictim
->isAlive())
1385 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1389 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1393 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1395 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1398 // Calculate absorb & resists
1402 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1404 //No more damage left, target absorbed and/or resisted all damage
1405 if (damage
> absorb
+ resist
)
1406 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1409 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1412 HitInfo
|= HITINFO_ABSORB
;
1415 HitInfo
|= HITINFO_RESIST
;
1416 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1420 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1425 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1428 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1429 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1431 // Actual log sent to client
1432 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1435 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1436 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1440 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1441 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1444 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1450 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1453 if(cleanDamage
.damage
)
1454 // Rage from damage received.
1455 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1456 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1462 void Unit::HandleEmoteCommand(uint32 anim_id
)
1464 WorldPacket
data( SMSG_EMOTE
, 12 );
1465 data
<< anim_id
<< GetGUID();
1466 WPAssert(data
.size() == 12);
1468 SendMessageToSet(&data
, true);
1471 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1473 uint32 newdamage
= 0;
1474 float armor
= pVictim
->GetArmor();
1475 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1476 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1478 if (armor
<0.0f
) armor
=0.0f
;
1480 float tmpvalue
= 0.0f
;
1481 if(getLevel() <= 59) //Level 1-59
1482 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1483 else if(getLevel() < 70) //Level 60-69
1484 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1486 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1490 if(tmpvalue
> 0.75f
)
1492 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1494 return (newdamage
> 1) ? newdamage
: 1;
1497 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1499 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1502 // Magic damage, check for resists
1503 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1505 // Get base victim resistance for school
1506 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1507 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1508 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1510 tmpvalue2
*= (float)(0.15f
/ getLevel());
1511 if (tmpvalue2
< 0.0f
)
1513 if (tmpvalue2
> 0.75f
)
1515 uint32 ran
= urand(0, 100);
1516 uint32 faq
[4] = {24,6,4,6};
1519 for (uint8 i
= 0; i
< 4; i
++)
1521 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1527 if (damagetype
== DOT
&& m
== 4)
1528 *resist
+= uint32(damage
- 1);
1530 *resist
+= uint32(damage
* m
/ 4);
1531 if(*resist
> damage
)
1537 int32 RemainingDamage
= damage
- *resist
;
1539 // absorb without mana cost
1540 int32 reflectDamage
= 0;
1541 Aura
* reflectAura
= NULL
;
1542 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1543 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1547 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1551 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1553 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1555 if (pVictim
->GetHealth() <= RemainingDamage
)
1557 int32 chance
= (*i
)->GetModifier()->m_amount
;
1558 if (roll_chance_i(chance
))
1560 pVictim
->CastSpell(pVictim
,31231,true);
1561 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1563 // with health > 10% lost health until health==10%, in other case no losses
1564 uint32 health10
= pVictim
->GetMaxHealth()/10;
1565 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1571 int32 currentAbsorb
;
1574 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1576 if(Unit
* caster
= (*i
)->GetCaster())
1578 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1579 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1581 switch((*k
)->GetModifier()->m_miscvalue
)
1583 case 5065: // Rank 1
1584 case 5064: // Rank 2
1585 case 5063: // Rank 3
1586 case 5062: // Rank 4
1587 case 5061: // Rank 5
1589 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1590 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1592 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1605 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1607 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1608 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1609 next
= vSchoolAbsorb
.begin();
1613 currentAbsorb
= RemainingDamage
;
1614 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1617 RemainingDamage
-= currentAbsorb
;
1619 // do not cast spells while looping auras; auras can get invalid otherwise
1621 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1623 // absorb by mana cost
1624 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1625 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1629 // check damage school mask
1630 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1633 int32 currentAbsorb
;
1634 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1635 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1637 currentAbsorb
= RemainingDamage
;
1639 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1640 if(Player
*modOwner
= GetSpellModOwner())
1641 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1643 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1644 if (currentAbsorb
> maxAbsorb
)
1645 currentAbsorb
= maxAbsorb
;
1647 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1648 if((*i
)->GetModifier()->m_amount
<= 0)
1650 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1651 next
= vManaShield
.begin();
1654 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1655 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1657 RemainingDamage
-= currentAbsorb
;
1660 // only split damage if not damaging yourself
1663 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1664 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1668 // check damage school mask
1669 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1672 // Damage can be splitted only if aura has an alive caster
1673 Unit
*caster
= (*i
)->GetCaster();
1674 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1677 int32 currentAbsorb
;
1678 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1679 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1681 currentAbsorb
= RemainingDamage
;
1683 RemainingDamage
-= currentAbsorb
;
1685 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1687 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1688 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1691 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1692 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1696 // check damage school mask
1697 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1700 // Damage can be splitted only if aura has an alive caster
1701 Unit
*caster
= (*i
)->GetCaster();
1702 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1705 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1707 RemainingDamage
-= splitted
;
1709 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1711 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1712 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1716 *absorb
= damage
- RemainingDamage
- *resist
;
1719 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
)
1721 MeleeHitOutcome outcome
;
1723 // If is casted Melee spell, calculate like physical
1725 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1727 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1729 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1730 pVictim
->AddThreat(this, 0.0f
);
1733 case MELEE_HIT_EVADE
:
1735 *hitInfo
|= HITINFO_MISS
;
1737 cleanDamage
->damage
= 0;
1740 case MELEE_HIT_MISS
:
1742 *hitInfo
|= HITINFO_MISS
;
1744 cleanDamage
->damage
= 0;
1745 if(GetTypeId()== TYPEID_PLAYER
)
1746 ((Player
*)this)->UpdateWeaponSkill(attType
);
1751 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1752 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1753 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1755 // -probability is between 0% and 40%
1757 float Probability
= 20;
1759 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1760 if( pVictim
->getLevel() < 30 )
1761 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1763 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1764 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1766 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1768 if(Probability
> 40.0f
)
1769 Probability
= 40.0f
;
1771 if(roll_chance_f(Probability
))
1772 CastSpell(pVictim
, 1604, true);
1775 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1776 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1778 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1780 // random durability for main hand weapon (ABSORB)
1781 if(damageAfterArmor
< *damage
)
1782 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1783 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1784 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1786 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1787 *damage
= damageAfterArmor
;
1790 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1791 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1793 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1794 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1798 case MELEE_HIT_BLOCK_CRIT
:
1799 case MELEE_HIT_CRIT
:
1803 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| 0x8;
1807 crit_bonus
= *damage
;
1809 // Apply crit_damage bonus for melee spells
1812 if(Player
* modOwner
= GetSpellModOwner())
1813 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1815 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1816 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1817 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1818 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1819 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1822 *damage
+= crit_bonus
;
1824 uint32 resilienceReduction
= 0;
1826 if(attType
== RANGED_ATTACK
)
1828 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1829 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1830 // Resilience - reduce crit damage
1831 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1832 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1836 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1837 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1838 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1839 // Resilience - reduce crit damage
1840 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1841 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1844 *damage
-= resilienceReduction
;
1845 cleanDamage
->damage
+= resilienceReduction
;
1847 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1848 ((Player
*)this)->UpdateWeaponSkill(attType
);
1850 ModifyAuraState(AURA_STATE_CRIT
, true);
1851 StartReactiveTimer( REACTIVE_CRIT
);
1853 if(getClass()==CLASS_HUNTER
)
1855 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1856 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1859 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1861 *blocked_amount
= pVictim
->GetShieldBlockValue();
1863 if (pVictim
->GetUnitBlockChance())
1864 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1866 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1868 //Only set VICTIMSTATE_BLOCK on a full block
1869 if (*blocked_amount
>= uint32(*damage
))
1871 *victimState
= VICTIMSTATE_BLOCKS
;
1872 *blocked_amount
= uint32(*damage
);
1875 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1878 ((Player
*)pVictim
)->UpdateDefense();
1880 // random durability for main hand weapon (BLOCK)
1881 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1882 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1885 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1886 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1890 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1893 case MELEE_HIT_PARRY
:
1895 if(attType
== RANGED_ATTACK
) //range attack - no parry
1897 outcome
= MELEE_HIT_NORMAL
;
1901 cleanDamage
->damage
+= *damage
;
1903 *victimState
= VICTIMSTATE_PARRY
;
1905 // instant (maybe with small delay) counter attack
1907 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1908 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1910 // after parry nearest next attack time will reduced at %40 from full attack time.
1911 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1912 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1914 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1915 float percent60
= 3*percent20
;
1916 // set to 20% if in range 20%...20+40% of full time
1917 if(offtime
> percent20
&& offtime
<= percent60
)
1919 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1921 // decrease at %40 from full time
1922 else if(offtime
> percent60
)
1924 offtime
-= 2*percent20
;
1925 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1931 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1932 float percent60
= 3*percent20
;
1933 // set to 20% if in range 20%...20+40% of full time
1934 if(basetime
> percent20
&& basetime
<= percent60
)
1936 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1938 // decrease at %40 from full time
1939 else if(basetime
> percent60
)
1941 basetime
-= 2*percent20
;
1942 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1948 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1950 // Update victim defense ?
1951 ((Player
*)pVictim
)->UpdateDefense();
1953 // random durability for main hand weapon (PARRY)
1954 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1955 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1958 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1960 if (pVictim
->getClass() == CLASS_HUNTER
)
1962 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1963 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1967 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1968 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1971 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1974 case MELEE_HIT_DODGE
:
1976 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1978 outcome
= MELEE_HIT_NORMAL
;
1982 cleanDamage
->damage
+= *damage
;
1984 *victimState
= VICTIMSTATE_DODGE
;
1986 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1987 ((Player
*)pVictim
)->UpdateDefense();
1989 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1991 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1993 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1994 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1998 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
2000 ((Player
*)this)->AddComboPoints(pVictim
, 1);
2001 StartReactiveTimer( REACTIVE_OVERPOWER
);
2004 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2007 case MELEE_HIT_BLOCK
:
2009 *blocked_amount
= pVictim
->GetShieldBlockValue();
2011 if (pVictim
->GetUnitBlockChance())
2012 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2014 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2016 //Only set VICTIMSTATE_BLOCK on a full block
2017 if (*blocked_amount
>= uint32(*damage
))
2019 *victimState
= VICTIMSTATE_BLOCKS
;
2020 *blocked_amount
= uint32(*damage
);
2023 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2026 ((Player
*)pVictim
)->UpdateDefense();
2028 // random durability for main hand weapon (BLOCK)
2029 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2030 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2033 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2034 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2038 case MELEE_HIT_GLANCING
:
2040 float reducePercent
= 1.0f
; //damage factor
2042 // calculate base values and mods
2043 float baseLowEnd
= 1.3;
2044 float baseHighEnd
= 1.2;
2045 switch(getClass()) // lowering base values for casters
2057 float maxLowEnd
= 0.6;
2058 switch(getClass()) // upper for melee classes
2062 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2066 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2067 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2068 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2070 // apply max/min bounds
2071 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2073 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2076 if ( highEnd
< 0.2f
) //high end limits
2078 if ( highEnd
> 0.99f
)
2081 if(lowEnd
> highEnd
) // prevent negative range size
2084 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2086 *damage
= uint32(reducePercent
* *damage
);
2087 cleanDamage
->damage
+= *damage
;
2088 *hitInfo
|= HITINFO_GLANCING
;
2091 case MELEE_HIT_CRUSHING
:
2093 // 150% normal damage
2094 *damage
+= (*damage
/ 2);
2095 cleanDamage
->damage
= *damage
;
2096 *hitInfo
|= HITINFO_CRUSHING
;
2097 // TODO: victimState, victim animation?
2104 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2105 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2107 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2108 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2111 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2112 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2114 cleanDamage
->damage
+= *blocked_amount
;
2116 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2118 //*hitInfo = 0x00010020;
2119 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2121 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2125 // update at damage Judgement aura duration that applied by attacker at victim
2128 AuraMap
const& vAuras
= pVictim
->GetAuras();
2129 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2131 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2132 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2133 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2135 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2136 (*itr
).second
->UpdateAuraDuration();
2141 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2143 // victim's damage shield
2144 // yet another hack to fix crashes related to the aura getting removed during iteration
2145 std::set
<Aura
*> alreadyDone
;
2146 uint32 removedAuras
= pVictim
->m_removedAuras
;
2147 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2148 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2151 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2153 alreadyDone
.insert(*i
);
2154 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2155 if (pVictim
->m_removedAuras
> removedAuras
)
2157 removedAuras
= pVictim
->m_removedAuras
;
2158 next
= vDamageShields
.begin();
2164 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2166 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2169 if (!pVictim
->isAlive())
2172 if(IsNonMeleeSpellCasted(false))
2176 if (attType
== BASE_ATTACK
)
2177 hitInfo
= HITINFO_NORMALSWING2
;
2178 else if (attType
== OFF_ATTACK
)
2179 hitInfo
= HITINFO_LEFTSWING
;
2181 return; // ignore ranged case
2183 uint32 extraAttacks
= m_extraAttacks
;
2185 // melee attack spell casted at main hand attack only
2186 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2188 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2190 // not recent extra attack only at any non extra attack (melee spell case)
2191 if(!extra
&& extraAttacks
)
2193 while(m_extraAttacks
)
2195 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2196 if(m_extraAttacks
> 0)
2204 VictimState victimState
= VICTIMSTATE_NORMAL
;
2206 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2207 uint32 blocked_dmg
= 0;
2208 uint32 absorbed_dmg
= 0;
2209 uint32 resisted_dmg
= 0;
2211 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2213 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2215 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2217 // not recent extra attack only at any non extra attack (miss case)
2218 if(!extra
&& extraAttacks
)
2220 while(m_extraAttacks
)
2222 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2223 if(m_extraAttacks
> 0)
2231 uint32 damage
= CalculateDamage (attType
, false);
2233 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2235 if (hitInfo
& HITINFO_MISS
)
2237 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2241 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2243 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2244 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2248 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2250 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2252 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2253 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2257 if (GetTypeId() == TYPEID_PLAYER
)
2258 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2259 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2261 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2262 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2264 // extra attack only at any non extra attack (normal case)
2265 if(!extra
&& extraAttacks
)
2267 while(m_extraAttacks
)
2269 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2270 if(m_extraAttacks
> 0)
2276 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2278 // Miss chance based on melee
2279 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2281 // Critical hit chance
2282 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2283 // this is to avoid compiler issue when declaring variables inside if
2284 float block_chance
, parry_chance
, dodge_chance
;
2286 // cannot be dodged/parried/blocked
2287 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2289 block_chance
= 0.0f
;
2290 parry_chance
= 0.0f
;
2291 dodge_chance
= 0.0f
;
2295 // parry can be avoided only by some abilities
2296 parry_chance
= pVictim
->GetUnitParryChance();
2297 // block might be bypassed by it as well
2298 block_chance
= pVictim
->GetUnitBlockChance();
2299 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2300 dodge_chance
= pVictim
->GetUnitDodgeChance();
2303 // Only players can have Talent&Spell bonuses
2304 if (GetTypeId() == TYPEID_PLAYER
)
2306 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2307 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2309 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents for speed
2311 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2312 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2314 // can't be dodged rogue finishing move
2315 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2317 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2319 dodge_chance
= 0.0f
;
2328 if(Player
* modOwner
= GetSpellModOwner())
2329 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2331 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2333 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
*100), int32(miss_chance
*100),int32(dodge_chance
*100),int32(parry_chance
*100),int32(block_chance
*100), true);
2336 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2338 // This is only wrapper
2340 // Miss chance based on melee
2341 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2343 // Critical hit chance
2344 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2346 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2347 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2348 float block_chance
= pVictim
->GetUnitBlockChance();
2349 float parry_chance
= pVictim
->GetUnitParryChance();
2351 // Useful if want to specify crit & miss chances for melee, else it could be removed
2352 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2354 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
*100), int32(miss_chance
*100), int32(dodge_chance
*100),int32(parry_chance
*100),int32(block_chance
*100), false);
2357 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, int32 crit_chance
, int32 miss_chance
, int32 dodge_chance
, int32 parry_chance
, int32 block_chance
, bool SpellCasted
) const
2359 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2360 return MELEE_HIT_EVADE
;
2362 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2363 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2365 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2366 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2368 // bonus from skills is 0.04%
2369 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2370 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2371 int32 sum
= 0, tmp
= 0;
2372 int32 roll
= urand (0, 10000);
2374 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2375 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2376 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2380 if (tmp
> 0 && roll
< (sum
+= tmp
))
2382 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2383 return MELEE_HIT_MISS
;
2386 // always crit against a sitting target (except 0 crit chance)
2387 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2389 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2390 return MELEE_HIT_CRIT
;
2395 // only players can't dodge if attacker is behind
2396 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2398 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2402 // Reduce dodge chance by attacker expertise rating
2403 if (GetTypeId() == TYPEID_PLAYER
)
2404 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2406 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2407 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2410 if ( (tmp
> 0) // check if unit _can_ dodge
2411 && ((tmp
-= skillBonus
) > 0)
2412 && roll
< (sum
+= tmp
))
2414 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2415 return MELEE_HIT_DODGE
;
2419 // parry & block chances
2421 // check if attack comes from behind, nobody can parry or block if attacker is behind
2422 if (!pVictim
->HasInArc(M_PI
,this))
2424 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2428 // Reduce parry chance by attacker expertise rating
2429 if (GetTypeId() == TYPEID_PLAYER
)
2430 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2432 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2434 int32 tmp
= int32(parry_chance
);
2435 if ( (tmp
> 0) // check if unit _can_ parry
2436 && ((tmp
-= skillBonus
) > 0)
2437 && (roll
< (sum
+= tmp
)))
2439 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2440 return MELEE_HIT_PARRY
;
2444 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2447 if ( (tmp
> 0) // check if unit _can_ block
2448 && ((tmp
-= skillBonus
) > 0)
2449 && (roll
< (sum
+= tmp
)))
2452 tmp
= crit_chance
+ skillBonus2
;
2453 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2455 if ( roll_chance_i(tmp
/100))
2457 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2458 return MELEE_HIT_BLOCK_CRIT
;
2461 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2462 return MELEE_HIT_BLOCK
;
2468 tmp
= crit_chance
+ skillBonus2
;
2470 if (tmp
> 0 && roll
< (sum
+= tmp
))
2472 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2473 return MELEE_HIT_CRIT
;
2476 // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
2477 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2478 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2479 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2480 getLevel() < pVictim
->getLevelForTarget(this) )
2482 // cap possible value (with bonuses > max skill)
2483 int32 skill
= attackerWeaponSkill
;
2484 int32 maxskill
= attackerMaxSkillValueForLevel
;
2485 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2487 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2488 tmp
= tmp
> 4000 ? 4000 : tmp
;
2489 if (roll
< (sum
+= tmp
))
2491 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2492 return MELEE_HIT_GLANCING
;
2496 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2498 // mobs can score crushing blows if they're 3 or more levels above victim
2499 // or when their weapon skill is 15 or more above victim's defense skill
2500 tmp
= victimDefenseSkill
;
2501 int32 tmpmax
= victimMaxSkillValueForLevel
;
2502 // having defense above your maximum (from items, talents etc.) has no effect
2503 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2504 // tmp = mob's level * 5 - player's current defense skill
2505 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2508 // add 2% chance per lacking skill point, min. is 15%
2509 tmp
= tmp
* 200 - 1500;
2510 if (roll
< (sum
+= tmp
))
2512 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2513 return MELEE_HIT_CRUSHING
;
2518 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2519 return MELEE_HIT_NORMAL
;
2522 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2524 float min_damage
, max_damage
;
2526 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2527 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2533 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2534 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2537 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2538 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2541 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2542 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2544 // Just for good manner
2552 if (min_damage
> max_damage
)
2554 std::swap(min_damage
,max_damage
);
2557 if(max_damage
== 0.0f
)
2560 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2563 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2565 if(spellProto
->spellLevel
<= 0)
2568 float LvlPenalty
= 0.0f
;
2570 if(spellProto
->spellLevel
< 20)
2571 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2572 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2573 if(LvlFactor
> 1.0f
)
2576 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2579 void Unit::SendAttackStart(Unit
* pVictim
)
2581 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2583 data
<< pVictim
->GetGUID();
2585 SendMessageToSet(&data
, true);
2586 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2589 void Unit::SendAttackStop(Unit
* victim
)
2594 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2595 data
.append(GetPackGUID());
2596 data
.append(victim
->GetPackGUID()); // can be 0x00...
2597 data
<< uint32(0); // can be 0x1
2598 SendMessageToSet(&data
, true);
2599 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2601 /*if(victim->GetTypeId() == TYPEID_UNIT)
2602 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2606 // Melee based spells can be miss, parry or dodge on this step
2607 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2608 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2610 // Calculate hit chance (more correct for chance mod)
2613 // PvP - PvE melee chances
2614 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2615 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2617 HitChance = 95 - leveldif;
2619 HitChance = 93 - (leveldif - 2) * lchance;
2621 // Hit chance depends from victim auras
2622 if(attType == RANGED_ATTACK)
2623 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2625 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2627 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2628 if(Player *modOwner = GetSpellModOwner())
2629 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2632 float miss_chance= 100.0f - HitChance;
2634 // Bonuses from attacker aura and ratings
2635 if (attType == RANGED_ATTACK)
2636 miss_chance -= m_modRangedHitChance;
2638 miss_chance -= m_modMeleeHitChance;
2640 // bonus from skills is 0.04%
2641 miss_chance -= skillDiff * 0.04f;
2643 // Limit miss chance from 0 to 60%
2644 if (miss_chance < 0.0f)
2646 if (miss_chance > 60.0f)
2651 // Melee based spells hit result calculations
2652 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2654 WeaponAttackType attType = BASE_ATTACK;
2656 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2657 attType = RANGED_ATTACK;
2659 // bonus from skills is 0.04% per skill Diff
2660 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2661 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2662 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2664 uint32 roll = urand (0, 10000);
2665 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2668 uint32 tmp = missChance;
2670 return SPELL_MISS_MISS;
2672 // Same spells cannot be parry/dodge
2673 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2674 return SPELL_MISS_NONE;
2676 // Ranged attack can`t miss too
2677 if (attType == RANGED_ATTACK)
2678 return SPELL_MISS_NONE;
2680 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2683 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2684 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2685 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2687 // Reduce dodge chance by attacker expertise rating
2688 if (GetTypeId() == TYPEID_PLAYER)
2689 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2690 if (dodgeChance < 0)
2693 // Can`t dodge from behind in PvP (but its possible in PvE)
2694 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2697 // Rogue talent`s cant be dodged
2698 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2699 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2701 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2703 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2713 return SPELL_MISS_DODGE;
2716 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2717 // Reduce parry chance by attacker expertise rating
2718 if (GetTypeId() == TYPEID_PLAYER)
2719 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2720 // Can`t parry from behind
2721 if (parryChance < 0 || attackFromBehind)
2726 return SPELL_MISS_PARRY;
2728 return SPELL_MISS_NONE;
2731 // TODO need use unit spell resistances in calculations
2732 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2734 // Can`t miss on dead target (on skinning for example)
2735 if (!pVictim
->isAlive())
2736 return SPELL_MISS_NONE
;
2738 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2739 // PvP - PvE spell misschances per leveldif > 2
2740 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2741 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2743 // Base hit chance from attacker and victim levels
2746 modHitChance
= 96 - leveldif
;
2748 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2750 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2751 if(Player
*modOwner
= GetSpellModOwner())
2752 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2753 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2754 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2755 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2756 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2757 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2758 if (IsAreaOfEffectSpell(spell
))
2759 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2760 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2761 if (IsDispelSpell(spell
))
2762 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2763 // Chance resist mechanic (select max value from every mechanic spell effect)
2764 int32 resist_mech
= 0;
2765 // Get effects mechanic and chance
2766 for(int eff
= 0; eff
< 3; ++eff
)
2768 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2771 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2772 if (resist_mech
< temp
)
2777 modHitChance
-=resist_mech
;
2779 // Chance resist debuff
2780 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2782 int32 HitChance
= modHitChance
* 100;
2783 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2784 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2786 // Decrease hit chance from victim rating bonus
2787 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2788 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2790 if (HitChance
< 100) HitChance
= 100;
2791 if (HitChance
> 9900) HitChance
= 9900;
2793 uint32 rand
= urand(0,10000);
2794 if (rand
> HitChance
)
2795 return SPELL_MISS_RESIST
;
2796 return SPELL_MISS_NONE
;
2799 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2801 // Return evade for units in evade mode
2802 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2803 return SPELL_MISS_EVADE
;
2805 // Check for immune (use charges)
2806 if (pVictim
->IsImmunedToSpell(spell
,true))
2807 return SPELL_MISS_IMMUNE
;
2809 // All positive spells can`t miss
2810 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2811 if (IsPositiveSpell(spell
->Id
))
2812 return SPELL_MISS_NONE
;
2814 // Check for immune (use charges)
2815 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2816 return SPELL_MISS_IMMUNE
;
2818 // Try victim reflect spell
2821 // specialized first
2822 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2823 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2825 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2827 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2828 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2830 if((*i
)->m_procCharges
> 0)
2832 --(*i
)->m_procCharges
;
2833 if((*i
)->m_procCharges
==0)
2834 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2836 return SPELL_MISS_REFLECT
;
2841 // generic reflection
2842 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2843 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2845 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2846 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2848 if((*i
)->m_procCharges
> 0)
2850 --(*i
)->m_procCharges
;
2851 if((*i
)->m_procCharges
==0)
2852 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2854 return SPELL_MISS_REFLECT
;
2859 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2860 for (int i
=0;i
<3;i
++)
2862 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2863 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2864 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2865 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2866 return SPELL_MISS_NONE
;
2869 // TODO need use this code for spell hit result calculation
2870 // now code commented for computability
2871 switch (spell
->DmgClass
)
2873 case SPELL_DAMAGE_CLASS_RANGED
:
2874 case SPELL_DAMAGE_CLASS_MELEE
:
2875 // return MeleeSpellHitResult(pVictim, spell);
2876 return SPELL_MISS_NONE
;
2877 case SPELL_DAMAGE_CLASS_NONE
:
2878 case SPELL_DAMAGE_CLASS_MAGIC
:
2879 return MagicSpellHitResult(pVictim
, spell
);
2881 return SPELL_MISS_NONE
;
2884 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2889 // Base misschance 5%
2890 float misschance
= 5.0f
;
2892 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2893 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2895 bool isNormal
= false;
2896 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2898 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2904 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2914 // PvP : PvE melee misschances per leveldif > 2
2915 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2917 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2921 // Hit chance from attacker based on ratings and auras
2922 float m_modHitChance
;
2923 if (attType
== RANGED_ATTACK
)
2924 m_modHitChance
= m_modRangedHitChance
;
2926 m_modHitChance
= m_modMeleeHitChance
;
2929 misschance
+= (leveldif
- m_modHitChance
);
2931 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2933 // Hit chance for victim based on ratings
2934 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2936 if (attType
== RANGED_ATTACK
)
2937 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2939 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2942 // Modify miss chance by victim auras
2943 if(attType
== RANGED_ATTACK
)
2944 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2946 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2948 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2949 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2950 misschance
-= skillBonus
* 0.04f
;
2952 // Limit miss chance from 0 to 60%
2953 if ( misschance
< 0.0f
)
2955 if ( misschance
> 60.0f
)
2961 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2963 if(GetTypeId() == TYPEID_PLAYER
)
2965 // in PvP use full skill instead current skill value
2966 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2967 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2968 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2969 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2973 return GetUnitMeleeSkill(target
);
2976 float Unit::GetUnitDodgeChance() const
2978 if(hasUnitState(UNIT_STAT_STUNNED
))
2980 if( GetTypeId() == TYPEID_PLAYER
)
2981 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2984 if(((Creature
const*)this)->isTotem())
2989 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2990 return dodge
> 0.0f
? dodge
: 0.0f
;
2995 float Unit::GetUnitParryChance() const
2997 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3000 float chance
= 0.0f
;
3002 if(GetTypeId() == TYPEID_PLAYER
)
3004 Player
const* player
= (Player
const*)this;
3005 if(player
->CanParry() )
3007 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3009 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3012 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3015 else if(GetTypeId() == TYPEID_UNIT
)
3017 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3020 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3024 return chance
> 0.0f
? chance
: 0.0f
;
3027 float Unit::GetUnitBlockChance() const
3029 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3032 if(GetTypeId() == TYPEID_PLAYER
)
3034 Player
const* player
= (Player
const*)this;
3035 if(player
->CanBlock() )
3037 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3038 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3039 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3041 // is player but has no block ability or no not broken shield equipped
3046 if(((Creature
const*)this)->isTotem())
3051 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3052 return block
> 0.0f
? block
: 0.0f
;
3057 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3061 if(GetTypeId() == TYPEID_PLAYER
)
3066 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3069 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3072 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3074 // Just for good manner
3083 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3087 if(attackType
== RANGED_ATTACK
)
3088 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3090 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3092 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3094 // reduce crit chance from Rating for players
3095 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3097 if (attackType
==RANGED_ATTACK
)
3098 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3100 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3108 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3111 if(GetTypeId() == TYPEID_PLAYER
)
3113 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3115 // feral or unarmed skill only for base attack
3116 if(attType
!= BASE_ATTACK
&& !item
)
3119 if(((Player
*)this)->IsInFeralForm())
3120 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3122 // weapon skill or (unarmed for base attack)
3123 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3125 // in PvP use full skill instead current skill value
3126 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3127 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3128 : ((Player
*)this)->GetSkillValue(skill
);
3129 // Modify value from ratings
3130 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3133 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3134 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3135 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3139 value
= GetUnitMeleeSkill(target
);
3143 void Unit::_UpdateSpells( uint32 time
)
3145 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3146 _UpdateAutoRepeatSpell();
3148 // remove finished spells from current pointers
3149 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3151 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3153 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3154 m_currentSpells
[i
] = NULL
; // remove pointer
3158 // TODO: Find a better way to prevent crash when multiple auras are removed.
3160 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3162 (*i
).second
->SetUpdated(false);
3164 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3170 // prevent double update
3171 if ((*i
).second
->IsUpdated())
3173 (*i
).second
->SetUpdated(true);
3174 (*i
).second
->Update( time
);
3175 // several auras can be deleted due to update
3178 if (m_Auras
.empty()) break;
3179 next
= m_Auras
.begin();
3185 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3189 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3204 if(!m_gameObj
.empty())
3206 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3207 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3210 //(*i)->Update( difftime );
3211 if( !(*ite1
)->isSpawned() )
3213 (*ite1
)->SetOwnerGUID(0);
3214 (*ite1
)->SetRespawnTime(0);
3216 dnext1
= m_gameObj
.erase(ite1
);
3224 void Unit::_UpdateAutoRepeatSpell()
3226 //check "realtime" interrupts
3227 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3229 // cancel wand shoot
3230 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3231 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3232 m_AutoRepeatFirstCast
= true;
3237 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3238 setAttackTimer(RANGED_ATTACK
,500);
3239 m_AutoRepeatFirstCast
= false;
3242 if (isAttackReady(RANGED_ATTACK
))
3244 // Check if able to cast
3245 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3247 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3252 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3253 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3255 // all went good, reset attack
3256 resetAttackTimer(RANGED_ATTACK
);
3260 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3262 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3264 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3266 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3268 // break same type spell if it is not delayed
3269 InterruptSpell(CSpellType
,false);
3271 // special breakage effects:
3274 case CURRENT_GENERIC_SPELL
:
3276 // generic spells always break channeled not delayed spells
3277 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3279 // autorepeat breaking
3280 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3282 // break autorepeat if not Auto Shot
3283 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3284 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3285 m_AutoRepeatFirstCast
= true;
3289 case CURRENT_CHANNELED_SPELL
:
3291 // channel spells always break generic non-delayed and any channeled spells
3292 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3293 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3295 // it also does break autorepeat if not Auto Shot
3296 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3297 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3298 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3301 case CURRENT_AUTOREPEAT_SPELL
:
3303 // only Auto Shoot does not break anything
3304 if (pSpell
->m_spellInfo
->Category
== 351)
3306 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3307 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3308 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3310 // special action: set first cast flag
3311 m_AutoRepeatFirstCast
= true;
3316 // other spell types don't break anything now
3320 // current spell (if it is still here) may be safely deleted now
3321 if (m_currentSpells
[CSpellType
])
3322 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3324 // set new current spell
3325 m_currentSpells
[CSpellType
] = pSpell
;
3326 pSpell
->SetReferencedFromCurrent(true);
3329 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3331 assert(spellType
< CURRENT_MAX_SPELL
);
3333 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3335 // send autorepeat cancel message for autorepeat spells
3336 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3338 if(GetTypeId()==TYPEID_PLAYER
)
3339 ((Player
*)this)->SendAutoRepeatCancel();
3342 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3343 m_currentSpells
[spellType
]->cancel();
3344 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3345 m_currentSpells
[spellType
] = NULL
;
3349 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3351 // We don't do loop here to explicitly show that melee spell is excluded.
3352 // Maybe later some special spells will be excluded too.
3354 // generic spells are casted when they are not finished and not delayed
3355 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3356 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3357 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3360 // channeled spells may be delayed, but they are still considered casted
3361 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3362 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3365 // autorepeat spells may be finished or delayed, but they are still considered casted
3366 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3372 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3374 // generic spells are interrupted if they are not finished or delayed
3375 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3377 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3378 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3379 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3380 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3381 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3384 // autorepeat spells are interrupted if they are not finished or delayed
3385 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3387 // send disable autorepeat packet in any case
3388 if(GetTypeId()==TYPEID_PLAYER
)
3389 ((Player
*)this)->SendAutoRepeatCancel();
3391 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3392 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3393 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3394 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3395 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3398 // channeled spells are interrupted if they are not finished, even if they are delayed
3399 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3401 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3402 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3403 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3404 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3408 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3410 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3411 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3412 return m_currentSpells
[i
];
3416 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3418 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3421 void Unit::SetInFront(Unit
const* target
)
3423 SetOrientation(GetAngle(target
));
3426 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3428 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3431 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3434 return c
->canSwim();
3436 return c
->canWalk() || c
->canFly();
3439 bool Unit::IsInWater() const
3441 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3444 bool Unit::IsUnderWater() const
3446 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3449 void Unit::DeMorph()
3451 SetDisplayId(GetNativeDisplayId());
3454 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3458 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3459 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3460 modifier
+= (*i
)->GetModifier()->m_amount
;
3465 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3467 float multiplier
= 1.0f
;
3469 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3470 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3471 multiplier
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3476 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3480 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3481 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3482 if ((*i
)->GetModifier()->m_amount
> modifier
)
3483 modifier
= (*i
)->GetModifier()->m_amount
;
3488 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3492 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3493 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3494 if ((*i
)->GetModifier()->m_amount
< modifier
)
3495 modifier
= (*i
)->GetModifier()->m_amount
;
3500 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3504 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3505 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3507 Modifier
* mod
= (*i
)->GetModifier();
3508 if (mod
->m_miscvalue
& misc_mask
)
3509 modifier
+= mod
->m_amount
;
3514 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3516 float multiplier
= 1.0f
;
3518 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3519 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3521 Modifier
* mod
= (*i
)->GetModifier();
3522 if (mod
->m_miscvalue
& misc_mask
)
3523 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3528 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3532 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3533 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3535 Modifier
* mod
= (*i
)->GetModifier();
3536 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3537 modifier
= mod
->m_amount
;
3543 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3547 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3548 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3550 Modifier
* mod
= (*i
)->GetModifier();
3551 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3552 modifier
= mod
->m_amount
;
3558 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3562 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3563 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3565 Modifier
* mod
= (*i
)->GetModifier();
3566 if (mod
->m_miscvalue
== misc_value
)
3567 modifier
+= mod
->m_amount
;
3572 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3574 float multiplier
= 1.0f
;
3576 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3577 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3579 Modifier
* mod
= (*i
)->GetModifier();
3580 if (mod
->m_miscvalue
== misc_value
)
3581 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3586 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3590 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3591 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3593 Modifier
* mod
= (*i
)->GetModifier();
3594 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3595 modifier
= mod
->m_amount
;
3601 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3605 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3606 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3608 Modifier
* mod
= (*i
)->GetModifier();
3609 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3610 modifier
= mod
->m_amount
;
3616 bool Unit::AddAura(Aura
*Aur
)
3618 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3619 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3620 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3626 if(Aur
->GetTarget() != this)
3628 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3629 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3630 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3635 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3637 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3638 AuraMap::iterator i
= m_Auras
.find( spair
);
3640 // take out same spell
3641 if (i
!= m_Auras
.end())
3643 // passive and persistent auras can stack with themselves any number of times
3644 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3646 // replace aura if next will > spell StackAmount
3647 if(aurSpellInfo
->StackAmount
)
3649 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3650 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3652 // if StackAmount==0 not allow auras from same caster
3655 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3657 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3659 // can be only single (this check done at _each_ aura add
3660 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3665 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3668 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3669 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3670 case SPELL_AURA_PERIODIC_LEECH
:
3671 case SPELL_AURA_PERIODIC_HEAL
:
3672 case SPELL_AURA_OBS_MOD_HEALTH
:
3673 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3674 case SPELL_AURA_PERIODIC_ENERGIZE
:
3675 case SPELL_AURA_OBS_MOD_MANA
:
3676 case SPELL_AURA_POWER_BURN_MANA
:
3678 default: // not allow
3679 // can be only single (this check done at _each_ aura add
3680 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3692 // passive auras stack with all (except passive spell proc auras)
3693 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3694 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3696 if (!RemoveNoStackAurasDueToAura(Aur
))
3699 return false; // couldn't remove conflicting aura with higher rank
3703 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3704 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3706 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3709 Unit
* caster
= Aur
->GetCaster();
3710 if(!caster
) // caster deleted and not required adding scAura
3713 bool restart
= false;
3714 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3715 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3717 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3718 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3720 if ((*itr
)->IsInUse())
3722 sLog
.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for IsSingleTargetSpell", (*itr
)->GetId(), (*itr
)->GetEffIndex(),Aur
->GetId(), Aur
->GetEffIndex());
3725 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3734 scAuras
.push_back(Aur
);
3740 // add aura, register in lists and arrays
3742 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3743 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3745 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3748 Aur
->ApplyModifier(true,true);
3749 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3753 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3755 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3758 AuraMap::iterator i
,next
;
3759 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3763 uint32 i_spellId
= (*i
).second
->GetId();
3764 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3766 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3768 RemoveAurasDueToSpell(i_spellId
);
3770 if( m_Auras
.empty() )
3773 next
= m_Auras
.begin();
3779 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3784 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3788 uint32 spellId
= Aur
->GetId();
3789 uint32 effIndex
= Aur
->GetEffIndex();
3791 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3793 AuraMap::iterator i
,next
;
3794 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3798 if (!(*i
).second
) continue;
3800 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3805 uint32 i_spellId
= i_spellProto
->Id
;
3807 if(IsPassiveSpell(i_spellId
))
3809 if(IsPassiveStackableSpell(i_spellId
))
3812 // passive non-stackable spells not stackable only with another rank of same spell
3813 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3817 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3819 if(i_spellId
== spellId
) continue;
3821 bool is_triggered_by_spell
= false;
3822 // prevent triggered aura of removing aura that triggered it
3823 for(int j
= 0; j
< 3; ++j
)
3824 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3825 is_triggered_by_spell
= true;
3826 if (is_triggered_by_spell
) continue;
3828 for(int j
= 0; j
< 3; ++j
)
3830 // prevent remove dummy triggered spells at next effect aura add
3831 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggered spell
3833 case SPELL_EFFECT_DUMMY
:
3836 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3841 if(is_triggered_by_spell
)
3844 // prevent remove form main spell by triggered passive spells
3845 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3847 case SPELL_AURA_MOD_SHAPESHIFT
:
3850 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3851 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3852 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3858 if(!is_triggered_by_spell
)
3860 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3862 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3864 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3866 // cannot remove higher rank
3867 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3868 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3871 // Its a parent aura (create this aura in ApplyModifier)
3872 if ((*i
).second
->IsInUse())
3874 sLog
.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i
->second
->GetId(), i
->second
->GetEffIndex(),Aur
->GetId(), Aur
->GetEffIndex());
3877 RemoveAurasDueToSpell(i_spellId
);
3879 if( m_Auras
.empty() )
3882 next
= m_Auras
.begin();
3884 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3886 // Its a parent aura (create this aura in ApplyModifier)
3887 if ((*i
).second
->IsInUse())
3889 sLog
.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i
->second
->GetId(), i
->second
->GetEffIndex(),Aur
->GetId(), Aur
->GetEffIndex());
3892 RemoveAurasDueToSpell(i_spellId
);
3894 if( m_Auras
.empty() )
3897 next
= m_Auras
.begin();
3899 // Potions stack aura by aura (elixirs/flask already checked)
3900 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3902 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3904 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3905 return false; // cannot remove higher rank
3907 // Its a parent aura (create this aura in ApplyModifier)
3908 if ((*i
).second
->IsInUse())
3910 sLog
.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i
->second
->GetId(), i
->second
->GetEffIndex(),Aur
->GetId(), Aur
->GetEffIndex());
3922 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3924 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3925 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3927 if(iter
->second
!=except
)
3930 iter
= m_Auras
.lower_bound(spair
);
3937 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3939 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3941 Aura
*aur
= iter
->second
;
3942 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3944 // Custom dispel case
3945 // Unstable Affliction
3946 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3948 int32 damage
= aur
->GetModifier()->m_amount
*9;
3949 uint64 caster_guid
= aur
->GetCasterGUID();
3952 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3954 // backfire damage and silence
3955 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3957 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3960 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3967 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3969 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3971 Aura
*aur
= iter
->second
;
3972 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3974 int32 basePoints
= aur
->GetBasePoints();
3975 // construct the new aura for the attacker
3976 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3980 // set its duration and maximum duration
3981 // max duration 2 minutes (in msecs)
3982 int32 dur
= aur
->GetAuraDuration();
3983 const int32 max_dur
= 2*MINUTE
*1000;
3984 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3985 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3987 // add the new aura to stealer
3988 stealer
->AddAura(new_aur
);
3990 // Remove aura as dispel
3991 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3998 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4000 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4002 if (iter
->second
->GetId() == spellId
)
4003 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4009 void Unit::RemoveAurasWithDispelType( DispelType type
)
4011 // Create dispel mask by dispel type
4012 uint32 dispelMask
= GetDispellMask(type
);
4013 // Dispel all existing auras vs current dispel type
4014 AuraMap
& auras
= GetAuras();
4015 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4017 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4018 if( (1<<spell
->Dispel
) & dispelMask
)
4021 RemoveAurasDueToSpell(spell
->Id
);
4022 itr
= auras
.begin();
4029 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4031 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4032 if(iter
!= m_Auras
.end())
4036 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4038 for (int i
= 0; i
< 3; ++i
)
4039 RemoveAura(spellId
,i
,except
);
4042 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4044 for (int k
=0; k
< 3; ++k
)
4046 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4047 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4049 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4052 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4060 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4062 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4064 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4071 void Unit::RemoveNotOwnSingleTargetAuras()
4073 // single target auras from other casters
4074 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4076 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4082 // single target auras at other targets
4083 AuraList
& scAuras
= GetSingleCastAuras();
4084 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4087 if (aura
->GetTarget()!=this)
4089 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4090 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4091 iter
= scAuras
.begin();
4099 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4101 Aura
* Aur
= i
->second
;
4102 SpellEntry
const* AurSpellInfo
= Aur
->GetSpellProto();
4104 Unit
* caster
= NULL
;
4105 if (IsSingleTargetSpell(AurSpellInfo
))
4107 caster
= Aur
->GetCaster();
4110 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4111 scAuras
.remove(Aur
);
4115 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4120 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4121 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4123 m_modAuras
[Aur
->GetModifier()->m_auraname
].remove(Aur
);
4127 Aur
->SetRemoveMode(mode
);
4128 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4129 // remove aura from list before to prevent deleting it before
4131 ++m_removedAuras
; // internal count used by unit update
4133 // Statue unsummoned at aura remove
4134 Totem
* statue
= NULL
;
4135 bool caster_channeled
= false;
4136 if(IsChanneledSpell(AurSpellInfo
))
4138 if(!caster
) // can be already located for IsSingleTargetSpell case
4139 caster
= Aur
->GetCaster();
4143 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4144 statue
= ((Totem
*)caster
);
4146 caster_channeled
= caster
==this;
4150 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4151 Aur
->ApplyModifier(false,true);
4155 if(caster_channeled
)
4156 RemoveAurasAtChanneledTarget (AurSpellInfo
);
4161 // only way correctly remove all auras from list
4162 if( m_Auras
.empty() )
4165 i
= m_Auras
.begin();
4168 void Unit::RemoveAllAuras()
4170 while (!m_Auras
.empty())
4172 AuraMap::iterator iter
= m_Auras
.begin();
4177 void Unit::RemoveAllAurasOnDeath()
4179 // used just after dieing to remove all visible auras
4180 // and disable the mods for the passive ones
4181 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4183 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4184 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4190 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4192 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4193 if (iter
!= m_Auras
.end())
4195 if (iter
->second
->GetAuraDuration() < delaytime
)
4196 iter
->second
->SetAuraDuration(0);
4198 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4199 iter
->second
->UpdateAuraDuration();
4200 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4204 void Unit::_RemoveAllAuraMods()
4206 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4208 (*i
).second
->ApplyModifier(false);
4212 void Unit::_ApplyAllAuraMods()
4214 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4216 (*i
).second
->ApplyModifier(true);
4220 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4222 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4223 if (iter
!= m_Auras
.end())
4224 return iter
->second
;
4228 void Unit::AddDynObject(DynamicObject
* dynObj
)
4230 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4233 void Unit::RemoveDynObject(uint32 spellid
)
4235 if(m_dynObjGUIDs
.empty())
4237 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4239 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4242 i
= m_dynObjGUIDs
.erase(i
);
4244 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4247 i
= m_dynObjGUIDs
.erase(i
);
4254 void Unit::RemoveAllDynObjects()
4256 while(!m_dynObjGUIDs
.empty())
4258 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4261 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4265 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4267 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4269 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4272 i
= m_dynObjGUIDs
.erase(i
);
4276 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4283 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4285 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4287 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4290 i
= m_dynObjGUIDs
.erase(i
);
4294 if (dynObj
->GetSpellId() == spellId
)
4301 void Unit::AddGameObject(GameObject
* gameObj
)
4303 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4304 m_gameObj
.push_back(gameObj
);
4305 gameObj
->SetOwnerGUID(GetGUID());
4308 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4310 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4312 // GO created by some spell
4313 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4315 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4316 // Need activate spell use for owner
4317 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4318 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4320 gameObj
->SetOwnerGUID(0);
4321 m_gameObj
.remove(gameObj
);
4324 gameObj
->SetRespawnTime(0);
4329 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4331 if(m_gameObj
.empty())
4333 std::list
<GameObject
*>::iterator i
, next
;
4334 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4337 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4339 (*i
)->SetOwnerGUID(0);
4342 (*i
)->SetRespawnTime(0);
4346 next
= m_gameObj
.erase(i
);
4353 void Unit::RemoveAllGameObjects()
4355 // remove references to unit
4356 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4358 (*i
)->SetOwnerGUID(0);
4359 (*i
)->SetRespawnTime(0);
4361 i
= m_gameObj
.erase(i
);
4365 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4367 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4368 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4369 data
.append(target
->GetPackGUID());
4370 data
.append(GetPackGUID());
4371 data
<< uint32(SpellID
);
4372 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4373 data
<< uint8(damageSchoolMask
); // spell school
4374 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4375 data
<< uint32(Resist
); // resist
4376 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
4377 data
<< uint8(0); // unk isFromAura
4378 data
<< uint32(Blocked
); // blocked
4379 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4380 data
<< uint8(0); // isDebug?
4381 SendMessageToSet( &data
, true );
4384 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4386 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4387 data
<< uint32(spellID
);
4388 data
<< uint64(GetGUID());
4389 data
<< uint8(0); // can be 0 or 1
4390 data
<< uint32(1); // target count
4391 // for(i = 0; i < target count; ++i)
4392 data
<< uint64(target
->GetGUID()); // target GUID
4393 data
<< uint8(missInfo
);
4395 SendMessageToSet(&data
, true);
4398 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4400 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4402 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4403 data
<< (uint32
)HitInfo
;
4404 data
.append(GetPackGUID());
4405 data
.append(target
->GetPackGUID());
4406 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4408 data
<< (uint8
)SwingType
; // count?
4410 // for(i = 0; i < SwingType; ++i)
4411 data
<< (uint32
)damageSchoolMask
;
4412 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4413 // still need to double check damage
4414 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4415 data
<< (uint32
)AbsorbDamage
;
4416 data
<< (uint32
)Resist
;
4419 data
<< (uint32
)TargetState
;
4421 if( AbsorbDamage
== 0 ) //also 0x3E8 = 0x3E8, check when that happens
4427 data
<< (uint32
)BlockedAmount
;
4429 SendMessageToSet( &data
, true );
4432 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4434 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4436 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4438 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4439 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4440 // That is the question though if it's fully correct
4441 if(procSpell
&& !isTriggeredSpell
)
4443 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4445 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4446 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4447 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4448 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4449 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4451 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4453 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4454 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4455 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4456 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4457 attType
= RANGED_ATTACK
;
4460 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4461 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4463 // Not much to do if no flags are set.
4466 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4467 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4468 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4471 // Now go on with a victim's events'n'auras
4472 // Not much to do if no flags are set or there is no victim
4473 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4475 // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set
4476 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4477 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4481 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4486 uint32 procAttacker
= PROC_FLAG_NONE
;
4487 uint32 procVictim
= PROC_FLAG_NONE
;
4491 case MELEE_HIT_EVADE
:
4493 case MELEE_HIT_MISS
:
4494 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4496 procAttacker
= PROC_FLAG_MISS
;
4499 case MELEE_HIT_BLOCK_CRIT
:
4500 case MELEE_HIT_CRIT
:
4501 if(spellCasted
&& attType
== BASE_ATTACK
)
4503 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4504 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4505 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4507 procVictim
|= PROC_FLAG_BLOCK
;
4508 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4511 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4513 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4514 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4518 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4519 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4522 case MELEE_HIT_PARRY
:
4523 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4524 procVictim
= PROC_FLAG_PARRY
;
4526 case MELEE_HIT_BLOCK
:
4527 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4528 procVictim
= PROC_FLAG_BLOCK
;
4530 case MELEE_HIT_DODGE
:
4531 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4532 procVictim
= PROC_FLAG_DODGE
;
4534 case MELEE_HIT_CRUSHING
:
4535 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4537 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4538 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4542 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4543 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4547 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4549 procAttacker
= PROC_FLAG_HIT_MELEE
;
4550 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4554 procAttacker
= PROC_FLAG_HIT_RANGED
;
4555 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4561 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4563 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4564 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4567 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4569 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4571 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4572 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4574 uint32 triggered_spell_id
= 0;
4575 Unit
* target
= pVictim
;
4576 int32 basepoints0
= 0;
4578 switch(hasteSpell
->SpellFamilyName
)
4580 case SPELLFAMILY_ROGUE
:
4582 switch(hasteSpell
->Id
)
4588 target
= SelectNearbyTarget();
4591 basepoints0
= damage
;
4592 triggered_spell_id
= 22482;
4600 // processed charge only counting case
4601 if(!triggered_spell_id
)
4604 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4608 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4613 if(!target
|| target
!=this && !target
->isAlive())
4616 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4620 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4622 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4624 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4625 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4630 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4632 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4633 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4635 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4636 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4638 uint32 triggered_spell_id
= 0;
4639 Unit
* target
= pVictim
;
4640 int32 basepoints0
= 0;
4642 switch(dummySpell
->SpellFamilyName
)
4644 case SPELLFAMILY_GENERIC
:
4646 switch (dummySpell
->Id
)
4652 // prevent damage back from weapon special attacks
4653 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4656 // return damage % to attacker but < 50% own total health
4657 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4658 if(basepoints0
> GetMaxHealth()/2)
4659 basepoints0
= GetMaxHealth()/2;
4661 triggered_spell_id
= 25997;
4669 // prevent chain of triggered spell from same triggered spell
4670 if(procSpell
&& procSpell
->Id
==26654)
4673 target
= SelectNearbyTarget();
4677 triggered_spell_id
= 26654;
4683 if (!procSpell
|| procSpell
->Id
== 24659)
4685 // Need remove one 24659 aura
4686 RemoveSingleAuraFromStack(24659, 0);
4687 RemoveSingleAuraFromStack(24659, 1);
4690 // Restless Strength
4693 // Need remove one 24662 aura
4694 RemoveSingleAuraFromStack(24662, 0);
4697 // Adaptive Warding (Frostfire Regalia set)
4705 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4706 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4708 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4710 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4720 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4722 case SPELL_SCHOOL_NORMAL
:
4723 case SPELL_SCHOOL_HOLY
:
4724 return false; // ignored
4725 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4726 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4727 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4728 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4729 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4737 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4745 for(int j
= 0; j
< 3; ++j
)
4747 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4756 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4758 case SPELL_SCHOOL_NORMAL
:
4759 return false; // ignore
4760 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4761 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4762 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4763 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4764 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4765 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4773 // Mana Leech (Passive) (Priest Pet Aura)
4777 target
= GetOwner();
4781 basepoints0
= int32(damage
* 2.5f
); // manaregen
4782 triggered_spell_id
= 34650;
4788 // Cast finish spell at last charge
4789 if (triggeredByAura
->m_procCharges
> 1)
4793 triggered_spell_id
= 33494;
4796 // Twisted Reflection (boss spell)
4798 triggered_spell_id
= 21064;
4800 // Vampiric Aura (boss spell)
4803 basepoints0
= 3 * damage
; // 300%
4804 if (basepoints0
< 0)
4807 triggered_spell_id
= 31285;
4811 // Aura of Madness (Darkmoon Card: Madness trinket)
4812 //=====================================================
4813 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4814 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4815 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4816 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4817 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4818 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4819 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4820 // 41011 Martyr Complex: +35 stamina (All classes)
4821 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4822 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4825 if(GetTypeId() != TYPEID_PLAYER
)
4828 // Select class defined buff
4831 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4832 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4834 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4835 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4838 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4839 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4841 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4842 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4845 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4846 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4847 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4848 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4850 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4851 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4854 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4856 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4857 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4865 if (roll_chance_i(10))
4866 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4870 // TODO: need find item for aura and triggered spells
4871 // Sunwell Exalted Caster Neck (??? neck)
4872 // cast ??? Light's Wrath if Exalted by Aldor
4873 // cast ??? Arcane Bolt if Exalted by Scryers*/
4875 return false; // disable for while
4878 if(GetTypeId() != TYPEID_PLAYER)
4881 // Get Aldor reputation rank
4882 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4885 triggered_spell_id = ???
4888 // Get Scryers reputation rank
4889 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4891 triggered_spell_id = ???
4896 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4897 // cast 45479 Light's Wrath if Exalted by Aldor
4898 // cast 45429 Arcane Bolt if Exalted by Scryers
4901 if(GetTypeId() != TYPEID_PLAYER
)
4904 // Get Aldor reputation rank
4905 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4908 triggered_spell_id
= 45479;
4911 // Get Scryers reputation rank
4912 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4914 triggered_spell_id
= 45429;
4919 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4920 // cast 45480 Light's Strength if Exalted by Aldor
4921 // cast 45428 Arcane Strike if Exalted by Scryers
4924 if(GetTypeId() != TYPEID_PLAYER
)
4927 // Get Aldor reputation rank
4928 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4931 triggered_spell_id
= 45480;
4934 // Get Scryers reputation rank
4935 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4937 triggered_spell_id
= 45428;
4942 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4943 // cast 45431 Arcane Insight if Exalted by Aldor
4944 // cast 45432 Light's Ward if Exalted by Scryers
4947 if(GetTypeId() != TYPEID_PLAYER
)
4950 // Get Aldor reputation rank
4951 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4954 triggered_spell_id
= 45432;
4957 // Get Scryers reputation rank
4958 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4961 triggered_spell_id
= 45431;
4966 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4967 // cast 45478 Light's Salvation if Exalted by Aldor
4968 // cast 45430 Arcane Surge if Exalted by Scryers
4971 if(GetTypeId() != TYPEID_PLAYER
)
4974 // Get Aldor reputation rank
4975 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4978 triggered_spell_id
= 45478;
4981 // Get Scryers reputation rank
4982 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4984 triggered_spell_id
= 45430;
4992 case SPELLFAMILY_MAGE
:
4995 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
4997 if (getPowerType() != POWER_MANA
)
5001 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5003 triggered_spell_id
= 29442;
5006 // Master of Elements
5007 if (dummySpell
->SpellIconID
== 1920)
5013 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5014 if( basepoints0
<=0 )
5018 triggered_spell_id
= 29077;
5021 switch(dummySpell
->Id
)
5030 switch (dummySpell
->Id
)
5032 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5033 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5034 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5035 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5036 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5038 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5042 triggered_spell_id
= 12654;
5048 //last charge and crit
5049 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5051 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5052 return true; // charge counting (will removed)
5055 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5056 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5061 case SPELLFAMILY_WARRIOR
:
5064 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5066 // check attack comes not from behind
5067 if (!HasInArc(M_PI
, pVictim
))
5070 triggered_spell_id
= 22858;
5075 case SPELLFAMILY_WARLOCK
:
5077 // Seed of Corruption
5078 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5080 Modifier
* mod
= triggeredByAura
->GetModifier();
5081 // if damage is more than need or target die from damage deal finish spell
5082 // FIX ME: not triggered currently at death
5083 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5085 // remember guid before aura delete
5086 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5088 // Remove aura (before cast for prevent infinite loop handlers)
5089 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5091 // Cast finish spell (triggeredByAura already not exist!)
5092 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5093 return true; // no hidden cooldown
5097 mod
->m_amount
-=damage
;
5100 // Seed of Corruption (Mobs cast) - no die req
5101 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5103 Modifier
* mod
= triggeredByAura
->GetModifier();
5104 // if damage is more than need deal finish spell
5105 if( mod
->m_amount
<= damage
)
5107 // remember guid before aura delete
5108 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5110 // Remove aura (before cast for prevent infinite loop handlers)
5111 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5113 // Cast finish spell (triggeredByAura already not exist!)
5114 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5115 return true; // no hidden cooldown
5118 mod
->m_amount
-=damage
;
5121 switch(dummySpell
->Id
)
5128 triggered_spell_id
= 17941;
5137 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5139 triggered_spell_id
= 30294;
5142 // Shadowflame (Voidheart Raiment set bonus)
5145 triggered_spell_id
= 37379;
5148 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5156 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5157 triggered_spell_id
= 37382;
5160 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5163 triggered_spell_id
= 37378;
5169 case SPELLFAMILY_PRIEST
:
5172 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5174 if(!pVictim
|| !pVictim
->isAlive())
5177 // pVictim is caster of aura
5178 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5182 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5183 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5184 return true; // no hidden cooldown
5186 switch(dummySpell
->Id
)
5191 if(!pVictim
|| !pVictim
->isAlive())
5194 // pVictim is caster of aura
5195 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5199 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5200 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5201 return true; // no hidden cooldown
5203 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5206 // Shadow Word: Pain
5207 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5208 triggered_spell_id
= 40441;
5210 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5211 triggered_spell_id
= 40440;
5218 // Oracle Healing Bonus ("Garments of the Oracle" set)
5222 basepoints0
= int32(damage
* 10/100);
5224 triggered_spell_id
= 26170;
5227 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5230 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5234 basepoints0
= int32(damage
* 2 / 100);
5236 triggered_spell_id
= 39373;
5239 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5242 triggered_spell_id
= 28810;
5248 case SPELLFAMILY_DRUID
:
5250 switch(dummySpell
->Id
)
5252 // Healing Touch (Dreamwalker Raiment set)
5256 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5258 triggered_spell_id
= 28742;
5261 // Healing Touch Refund (Idol of Longevity trinket)
5265 triggered_spell_id
= 28848;
5268 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5273 triggered_spell_id
= 37238;
5276 // Druid Tier 6 Trinket
5282 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5284 triggered_spell_id
= 40445;
5288 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5290 triggered_spell_id
= 40446;
5293 // Mangle (cat/bear)
5294 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5296 triggered_spell_id
= 40452;
5302 if (!roll_chance_f(chance
))
5311 // Deadly Interrupt Effect
5312 triggered_spell_id
= 32747;
5318 case SPELLFAMILY_ROGUE
:
5320 switch(dummySpell
->Id
)
5322 // Deadly Throw Interrupt
5325 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5329 triggered_spell_id
= 32747;
5334 if( dummySpell
->SpellIconID
== 2116 )
5339 // only rogue's finishing moves (maybe need additional checks)
5340 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5341 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5345 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5346 if(basepoints0
<= 0)
5350 triggered_spell_id
= 31663;
5355 case SPELLFAMILY_HUNTER
:
5357 // Thrill of the Hunt
5358 if ( dummySpell
->SpellIconID
== 2236 )
5364 basepoints0
= procSpell
->manaCost
* 40/100;
5365 if(basepoints0
<= 0)
5369 triggered_spell_id
= 34720;
5374 case SPELLFAMILY_PALADIN
:
5376 // Seal of Righteousness - melee proc dummy
5377 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5379 if(GetTypeId() != TYPEID_PLAYER
)
5383 switch (triggeredByAura
->GetId())
5385 case 21084: spellId
= 25742; break; // Rank 1
5386 case 20287: spellId
= 25740; break; // Rank 2
5387 case 20288: spellId
= 25739; break; // Rank 3
5388 case 20289: spellId
= 25738; break; // Rank 4
5389 case 20290: spellId
= 25737; break; // Rank 5
5390 case 20291: spellId
= 25736; break; // Rank 6
5391 case 20292: spellId
= 25735; break; // Rank 7
5392 case 20293: spellId
= 25713; break; // Rank 8
5393 case 27155: spellId
= 27156; break; // Rank 9
5395 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5398 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5399 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5401 float damageBasePoints
;
5402 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5404 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5406 // one hand weapon/no weapon
5407 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5409 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5411 // apply damage bonuses manually
5412 if(damagePoint
>= 0)
5413 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5415 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5416 return true; // no hidden cooldown
5418 // Seal of Blood do damage trigger
5419 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5421 switch(triggeredByAura
->GetEffIndex())
5424 // prevent chain triggering
5425 if(procSpell
&& procSpell
->Id
==31893 )
5428 triggered_spell_id
= 31893;
5433 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5435 triggered_spell_id
= 32221;
5441 switch(dummySpell
->Id
)
5443 // Holy Power (Redemption Armor set)
5449 // Set class defined buff
5450 switch (pVictim
->getClass())
5456 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5460 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5464 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5467 triggered_spell_id
= 28790; // Increases the friendly target's armor
5477 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5480 triggered_spell_id
= 31803;
5487 // if healed by another unit (pVictim)
5492 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5494 triggered_spell_id
= 31786;
5497 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5505 // Flash of light/Holy light
5506 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5508 triggered_spell_id
= 40471;
5512 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5514 triggered_spell_id
= 40472;
5520 if (!roll_chance_f(chance
))
5528 case SPELLFAMILY_SHAMAN
:
5530 switch(dummySpell
->Id
)
5532 // Totemic Power (The Earthshatterer set)
5538 // Set class defined buff
5539 switch (pVictim
->getClass())
5545 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5549 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5553 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5556 triggered_spell_id
= 28827; // Increases the friendly target's armor
5563 // Lesser Healing Wave (Totem of Flowing Water Relic)
5567 triggered_spell_id
= 28850;
5570 // Windfury Weapon (Passive) 1-5 Ranks
5573 if(GetTypeId()!=TYPEID_PLAYER
)
5576 if(!castItem
|| !castItem
->IsEquipped())
5579 // custom cooldown processing case
5580 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5584 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5586 case 283: spellId
= 33757; break; //1 Rank
5587 case 284: spellId
= 33756; break; //2 Rank
5588 case 525: spellId
= 33755; break; //3 Rank
5589 case 1669:spellId
= 33754; break; //4 Rank
5590 case 2636:spellId
= 33727; break; //5 Rank
5593 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5594 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5599 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5600 if(!windfurySpellEntry
)
5602 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5606 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5609 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5611 // Value gained from additional AP
5612 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5613 triggered_spell_id
= 33750;
5618 // Value gained from additional AP
5619 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5620 triggered_spell_id
= 25504;
5623 // apply cooldown before cast to prevent processing itself
5625 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5628 for ( uint32 i
= 0; i
<2; ++i
)
5629 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5633 // Shaman Tier 6 Trinket
5640 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5642 triggered_spell_id
= 40465; // Lightning Bolt
5645 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5647 triggered_spell_id
= 40465; // Lesser Healing Wave
5650 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5652 triggered_spell_id
= 40466; // Stormstrike
5658 if (!roll_chance_f(chance
))
5667 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5669 if(GetTypeId() != TYPEID_PLAYER
)
5673 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5675 triggered_spell_id
= 379;
5678 // Lightning Overload
5679 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5681 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5684 // custom cooldown processing case
5685 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5689 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5690 switch (procSpell
->Id
)
5693 case 403: spellId
= 45284; break; // Rank 1
5694 case 529: spellId
= 45286; break; // Rank 2
5695 case 548: spellId
= 45287; break; // Rank 3
5696 case 915: spellId
= 45288; break; // Rank 4
5697 case 943: spellId
= 45289; break; // Rank 5
5698 case 6041: spellId
= 45290; break; // Rank 6
5699 case 10391: spellId
= 45291; break; // Rank 7
5700 case 10392: spellId
= 45292; break; // Rank 8
5701 case 15207: spellId
= 45293; break; // Rank 9
5702 case 15208: spellId
= 45294; break; // Rank 10
5703 case 25448: spellId
= 45295; break; // Rank 11
5704 case 25449: spellId
= 45296; break; // Rank 12
5706 case 421: spellId
= 45297; break; // Rank 1
5707 case 930: spellId
= 45298; break; // Rank 2
5708 case 2860: spellId
= 45299; break; // Rank 3
5709 case 10605: spellId
= 45300; break; // Rank 4
5710 case 25439: spellId
= 45301; break; // Rank 5
5711 case 25442: spellId
= 45302; break; // Rank 6
5713 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5716 // No thread generated mod
5717 SpellModifier
*mod
= new SpellModifier
;
5718 mod
->op
= SPELLMOD_THREAT
;
5720 mod
->type
= SPELLMOD_PCT
;
5721 mod
->spellId
= dummySpell
->Id
;
5723 mod
->lastAffected
= NULL
;
5724 mod
->mask
= 0x0000000000000003LL
;
5726 ((Player
*)this)->AddSpellMod(mod
, true);
5728 // Remove cooldown (Chain Lightning - have Category Recovery time)
5729 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5730 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5732 // Hmmm.. in most case spells already set half basepoints but...
5733 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5735 // 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.
5736 // So - no add changes :)
5737 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5739 ((Player
*)this)->AddSpellMod(mod
, false);
5741 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5742 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5752 // processed charge only counting case
5753 if(!triggered_spell_id
)
5756 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5760 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5765 if(!target
|| target
!=this && !target
->isAlive())
5768 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5772 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5774 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5776 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5777 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5782 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5784 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5786 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5787 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5789 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5790 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5791 int32 basepoints0
= 0;
5793 switch(auraSpellInfo
->SpellFamilyName
)
5795 case SPELLFAMILY_GENERIC
:
5797 switch(auraSpellInfo
->Id
)
5799 // Aegis of Preservation
5801 //Aegis Heal (instead non-existed triggered spell)
5802 triggered_spell_id
= 23781;
5805 // Elune's Touch (moonkin mana restore)
5808 // Elune's Touch (instead non-existed triggered spell)
5809 triggered_spell_id
= 33926;
5810 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5817 // only for cast with mana price
5818 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5820 break; // fall through to normal cast
5825 // at melee hit call std triggered spell
5826 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5827 break; // fall through to normal cast
5829 // Mark of Conquest - else (at range hit) called custom case
5830 triggered_spell_id
= 39557;
5836 return true; // nothing to do
5837 // Forgotten Knowledge (Blade of Wizardry)
5839 // only for harmful enemy targeted spell
5840 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5842 break; // fall through to normal cast
5843 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5846 // proc only at non-crit hits
5847 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5849 break; // fall through to normal cast
5851 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5857 //only periodic damage can trigger spell
5859 for(int j
= 0; j
< 3; ++j
)
5861 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5862 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5863 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5872 break; // fall through to normal cast
5874 // Evasive Maneuvers (Commendation of Kael'thas)
5877 // damage taken that reduces below 35% health
5878 // does NOT mean you must have been >= 35% before
5879 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5881 break; // fall through to normal cast
5885 switch(triggered_spell_id
)
5890 // applied only for main target
5891 if(!pVictim
|| pVictim
!= getVictim())
5894 // continue normal case
5897 // Shamanistic Rage triggered spell
5899 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5904 case SPELLFAMILY_MAGE
:
5906 switch(auraSpellInfo
->SpellIconID
)
5910 //Blazing Speed (instead non-existed triggered spell)
5911 triggered_spell_id
= 31643;
5915 switch(auraSpellInfo
->Id
)
5917 // Persistent Shield (Scarab Brooch)
5919 basepoints0
= int32(damage
* 0.15f
);
5924 case SPELLFAMILY_WARRIOR
:
5927 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5929 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5930 //and effect[1]==TriggerSpell
5931 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5933 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5936 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5937 break; // fall through to normal cast
5941 case SPELLFAMILY_WARLOCK
:
5944 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5946 // last case for Hellfire that damage caster also but don't must stun caster
5947 if( pVictim
== this )
5952 switch (triggeredByAura
->GetId())
5954 case 18096: chance
= 13.0f
; break;
5955 case 18073: chance
= 26.0f
; break;
5957 if (!roll_chance_f(chance
))
5960 // Pyroclasm (instead non-existed triggered spell)
5961 triggered_spell_id
= 18093;
5966 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5969 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5970 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5972 //Improved Drain Soul
5973 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5975 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5976 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5978 CastCustomSpell(this, 18371, &basepoints0
, NULL
, NULL
, true, castItem
, triggeredByAura
);
5982 // Not remove charge (aura removed on death in any cases)
5983 // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
5988 case SPELLFAMILY_PRIEST
:
5991 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
5993 switch (triggeredByAura
->GetSpellProto()->Id
)
5995 case 27811: triggered_spell_id
= 27813; break;
5996 case 27815: triggered_spell_id
= 27817; break;
5997 case 27816: triggered_spell_id
= 27818; break;
5999 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6003 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6004 basepoints0
= heal_amount
/3;
6009 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
==7958)
6011 switch(triggeredByAura
->GetSpellProto()->Id
)
6014 triggered_spell_id
= 28377; break; // Rank 1
6016 triggered_spell_id
= 28378; break; // Rank 2
6018 triggered_spell_id
= 28379; break; // Rank 3
6020 triggered_spell_id
= 28380; break; // Rank 4
6022 triggered_spell_id
= 28381; break; // Rank 5
6024 triggered_spell_id
= 28382; break; // Rank 6
6026 triggered_spell_id
= 28385; break; // Rank 7
6028 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6036 case SPELLFAMILY_DRUID
:
6038 switch(auraSpellInfo
->Id
)
6040 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6043 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6045 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6046 triggered_spell_id
= 34299;
6049 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6056 triggered_spell_id
=37340; break;// Ursine Blessing
6058 triggered_spell_id
=37341; break;// Feline Blessing
6060 triggered_spell_id
=37342; break;// Slyvan Blessing
6062 triggered_spell_id
=37343; break;// Lunar Blessing
6064 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6075 case SPELLFAMILY_ROGUE
:
6077 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6079 switch(auraSpellInfo
->SpellIconID
)
6084 // skip non offhand attacks
6085 if(attackType
!=OFF_ATTACK
)
6087 break; // fall through to normal cast
6093 case SPELLFAMILY_PALADIN
:
6095 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6097 switch(auraSpellInfo
->Id
)
6099 // Lightning Capacitor
6102 // trinket ProcTriggerSpell but for safe checks for player
6103 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6106 if(((Player
*)this)->HasSpellCooldown(37657))
6110 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6111 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6112 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6116 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6117 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6118 if((*itr
)->GetId()==37658)
6121 // release at 3 aura in stack
6123 return true; // main triggered spell casted anyway
6125 RemoveAurasDueToSpell(37658);
6126 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6131 // Healing Trance (instead non-existed triggered spell)
6132 triggered_spell_id
= 37706;
6135 // HoTs on Heals (Fel Reaver's Piston trinket)
6138 // at direct heal effect
6139 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6142 // single proc at time
6143 AuraList
const& scAuras
= GetSingleCastAuras();
6144 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6145 if((*itr
)->GetId()==triggered_spell_id
)
6148 // positive cast at victim instead self
6153 switch(auraSpellInfo
->SpellIconID
)
6157 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6165 // procspell is triggered spell but we need mana cost of original casted spell
6166 uint32 originalSpellId
= procSpell
->Id
;
6169 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6171 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6173 switch(procSpell
->Id
)
6175 case 25914: originalSpellId
= 20473; break;
6176 case 25913: originalSpellId
= 20929; break;
6177 case 25903: originalSpellId
= 20930; break;
6178 case 27175: originalSpellId
= 27174; break;
6179 case 33074: originalSpellId
= 33072; break;
6181 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6187 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6190 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6194 // percent stored in effect 1 (class scripts) base points
6195 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6197 basepoints0
= originalSpell
->manaCost
*percent
/100;
6198 triggered_spell_id
= 20272;
6207 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6209 switch(auraSpellInfo
->SpellIconID
)
6211 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6214 if(!pVictim
|| !pVictim
->isAlive())
6217 switch(triggeredByAura
->GetSpellProto()->Id
)
6220 triggered_spell_id
= 20268; // Rank 1
6223 triggered_spell_id
= 20352; // Rank 2
6226 triggered_spell_id
= 20353; // Rank 3
6229 triggered_spell_id
= 27165; // Rank 4
6232 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6236 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6237 return true; // no hidden cooldown
6239 //Judgement of Light
6242 if(!pVictim
|| !pVictim
->isAlive())
6245 // overwrite non existing triggered spell call in spell.dbc
6246 switch(triggeredByAura
->GetSpellProto()->Id
)
6249 triggered_spell_id
= 20267; // Rank 1
6252 triggered_spell_id
= 20341; // Rank 2
6255 triggered_spell_id
= 20342; // Rank 3
6258 triggered_spell_id
= 20343; // Rank 4
6261 triggered_spell_id
= 27163; // Rank 5
6264 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6267 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6268 return true; // no hidden cooldown
6272 // custom check for proc spell
6273 switch(auraSpellInfo
->Id
)
6275 // Bonus Healing (item spell)
6278 if(!pVictim
|| !pVictim
->isAlive())
6281 // bonus if health < 50%
6282 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6285 // cast at target positive spell
6290 switch(triggered_spell_id
)
6294 // prevent chain of triggered spell from same triggered spell
6295 if(procSpell
&& procSpell
->Id
==20424)
6301 case SPELLFAMILY_SHAMAN
:
6303 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6305 switch(auraSpellInfo
->SpellIconID
)
6309 switch(auraSpellInfo
->Id
)
6311 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6313 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6314 triggered_spell_id
= 23552;
6318 case 23552: // Lightning Shield - trigger shield damage
6320 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6321 triggered_spell_id
= 27635;
6328 // Mana Surge (Shaman T1 bonus)
6334 basepoints0
= procSpell
->manaCost
* 35/100;
6335 triggered_spell_id
= 23571;
6342 if(GetTypeId()!=TYPEID_PLAYER
)
6345 // damage taken that reduces below 30% health
6346 // does NOT mean you must have been >= 30% before
6347 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6350 triggered_spell_id
= 31616;
6352 // need check cooldown now
6353 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6356 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6358 if(pVictim
&& pVictim
->isAlive())
6359 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6365 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6366 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
==7358)
6373 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
==37)
6375 // overwrite non existing triggered spell call in spell.dbc
6376 switch(triggeredByAura
->GetSpellProto()->Id
)
6379 triggered_spell_id
= 26364; break; // Rank 1
6381 triggered_spell_id
= 26365; break; // Rank 2
6383 triggered_spell_id
= 26366; break; // Rank 3
6385 triggered_spell_id
= 26367; break; // Rank 4
6387 triggered_spell_id
= 26369; break; // Rank 5
6389 triggered_spell_id
= 26370; break; // Rank 6
6391 triggered_spell_id
= 26363; break; // Rank 7
6393 triggered_spell_id
= 26371; break; // Rank 8
6395 triggered_spell_id
= 26372; break; // Rank 9
6397 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6408 // standard non-dummy case
6409 if(!triggered_spell_id
)
6411 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6415 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6419 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6423 // not allow proc extra attack spell at extra attack
6424 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6427 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6431 if(!target
|| target
!=this && !target
->isAlive())
6435 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6437 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6439 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6440 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6445 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6447 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6449 if(!pVictim
|| !pVictim
->isAlive())
6452 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6453 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6455 uint32 triggered_spell_id
= 0;
6459 case 836: // Improved Blizzard (Rank 1)
6461 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6463 triggered_spell_id
= 12484;
6466 case 988: // Improved Blizzard (Rank 2)
6468 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6470 triggered_spell_id
= 12485;
6473 case 989: // Improved Blizzard (Rank 3)
6475 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6477 triggered_spell_id
= 12486;
6480 case 4086: // Improved Mend Pet (Rank 1)
6481 case 4087: // Improved Mend Pet (Rank 2)
6483 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6484 if(!roll_chance_i(chance
))
6487 triggered_spell_id
= 24406;
6490 case 4533: // Dreamwalker Raiment 2 pieces bonus
6493 if (!roll_chance_i(50))
6496 switch (pVictim
->getPowerType())
6498 case POWER_MANA
: triggered_spell_id
= 28722; break;
6499 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6500 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6506 case 4537: // Dreamwalker Raiment 6 pieces bonus
6507 triggered_spell_id
= 28750; // Blessing of the Claw
6509 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6510 triggered_spell_id
= 37445; // Mana Surge
6515 if(!triggered_spell_id
)
6518 // standard non-dummy case
6519 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6523 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6527 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6530 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6532 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6533 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6538 void Unit::setPowerType(Powers new_powertype
)
6540 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6542 if(GetTypeId() == TYPEID_PLAYER
)
6544 if(((Player
*)this)->GetGroup())
6545 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6547 else if(((Creature
*)this)->isPet())
6549 Pet
*pet
= ((Pet
*)this);
6550 if(pet
->isControlled())
6552 Unit
*owner
= GetOwner();
6553 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6554 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6558 switch(new_powertype
)
6564 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6565 SetPower( POWER_RAGE
,0);
6568 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6569 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6572 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6573 SetPower( POWER_ENERGY
,0);
6575 case POWER_HAPPINESS
:
6576 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6577 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6582 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6584 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6587 static uint64 guid
= 0; // prevent repeating spam same faction problem
6589 if(GetGUID() != guid
)
6591 if(GetTypeId() == TYPEID_PLAYER
)
6592 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6594 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6601 bool Unit::IsHostileTo(Unit
const* unit
) const
6603 // always non-hostile to self
6607 // always non-hostile to GM in GM mode
6608 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6611 // always hostile to enemy
6612 if(getVictim()==unit
|| unit
->getVictim()==this)
6615 // test pet/charm masters instead pers/charmeds
6616 Unit
const* testerOwner
= GetCharmerOrOwner();
6617 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6619 // always hostile to owner's enemy
6620 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6623 // always hostile to enemy owner
6624 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6627 // always hostile to owner of owner's enemy
6628 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6631 Unit
const* tester
= testerOwner
? testerOwner
: this;
6632 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6634 // always non-hostile to target with common owner, or to owner/pet
6638 // special cases (Duel, etc)
6639 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6641 Player
const* pTester
= (Player
const*)tester
;
6642 Player
const* pTarget
= (Player
const*)target
;
6645 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6649 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6653 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6657 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6661 // Green/Blue (can't attack)
6662 if(pTester
->GetTeam()==pTarget
->GetTeam())
6665 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6666 return pTester
->IsPvP() && pTarget
->IsPvP();
6669 // faction base cases
6670 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6671 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6672 if(!tester_faction
|| !target_faction
)
6675 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6678 // PvC forced reaction and reputation case
6679 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6682 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6683 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6684 return forceItr
->second
<= REP_HOSTILE
;
6686 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6687 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6688 if(raw_target_faction
->reputationListID
>=0)
6689 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6690 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6692 // CvP forced reaction and reputation case
6693 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6696 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6697 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6698 return forceItr
->second
<= REP_HOSTILE
;
6700 // apply reputation state
6701 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6702 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6703 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6706 // common faction based case (CvC,PvC,CvP)
6707 return tester_faction
->IsHostileTo(*target_faction
);
6710 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6712 // always friendly to self
6716 // always friendly to GM in GM mode
6717 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6720 // always non-friendly to enemy
6721 if(getVictim()==unit
|| unit
->getVictim()==this)
6724 // test pet/charm masters instead pers/charmeds
6725 Unit
const* testerOwner
= GetCharmerOrOwner();
6726 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6728 // always non-friendly to owner's enemy
6729 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6732 // always non-friendly to enemy owner
6733 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6736 // always non-friendly to owner of owner's enemy
6737 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6740 Unit
const* tester
= testerOwner
? testerOwner
: this;
6741 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6743 // always friendly to target with common owner, or to owner/pet
6747 // special cases (Duel)
6748 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6750 Player
const* pTester
= (Player
const*)tester
;
6751 Player
const* pTarget
= (Player
const*)target
;
6754 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6758 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6762 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6766 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6770 // Green/Blue (non-attackable)
6771 if(pTester
->GetTeam()==pTarget
->GetTeam())
6774 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6775 return !pTarget
->IsPvP();
6778 // faction base cases
6779 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6780 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6781 if(!tester_faction
|| !target_faction
)
6784 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6787 // PvC forced reaction and reputation case
6788 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6791 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6792 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6793 return forceItr
->second
>= REP_FRIENDLY
;
6795 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6796 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6797 if(raw_target_faction
->reputationListID
>=0)
6798 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6799 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6801 // CvP forced reaction and reputation case
6802 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6805 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6806 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6807 return forceItr
->second
>= REP_FRIENDLY
;
6809 // apply reputation state
6810 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6811 if(raw_tester_faction
->reputationListID
>=0 )
6812 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6815 // common faction based case (CvC,PvC,CvP)
6816 return tester_faction
->IsFriendlyTo(*target_faction
);
6819 bool Unit::IsHostileToPlayers() const
6821 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6825 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6826 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6829 return my_faction
->IsHostileToPlayers();
6832 bool Unit::IsNeutralToAll() const
6834 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6838 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6839 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6842 return my_faction
->IsNeutralToAll();
6845 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6847 if(!victim
|| victim
== this)
6850 // dead units can neither attack nor be attacked
6851 if(!isAlive() || !victim
->isAlive())
6854 // player cannot attack in mount state
6855 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6858 // nobody can attack GM in GM-mode
6859 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6861 if(((Player
*)victim
)->isGameMaster())
6866 if(((Creature
*)victim
)->IsInEvadeMode())
6870 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6871 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6872 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6876 if (m_attacking
== victim
)
6878 // switch to melee attack from ranged/magic
6879 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6881 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6882 SendAttackStart(victim
);
6891 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6894 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6895 m_attacking
= victim
;
6896 m_attacking
->_addAttacker(this);
6898 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6899 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6901 if(GetTypeId()==TYPEID_UNIT
)
6903 WorldPacket
data(SMSG_AI_REACTION
, 12);
6905 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6906 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6908 ((Creature
*)this)->CallAssistance();
6909 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6912 // delay offhand weapon attack to next attack time
6913 if(haveOffhandWeapon())
6914 resetAttackTimer(OFF_ATTACK
);
6917 SendAttackStart(victim
);
6922 bool Unit::AttackStop()
6927 Unit
* victim
= m_attacking
;
6929 m_attacking
->_removeAttacker(this);
6933 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6935 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6937 InterruptSpell(CURRENT_MELEE_SPELL
);
6939 if( GetTypeId()==TYPEID_UNIT
)
6941 // reset call assistance
6942 ((Creature
*)this)->SetNoCallAssistance(false);
6945 SendAttackStop(victim
);
6950 void Unit::CombatStop(bool cast
)
6952 if(cast
& IsNonMeleeSpellCasted(false))
6953 InterruptNonMeleeSpells(false);
6956 RemoveAllAttackers();
6957 if( GetTypeId()==TYPEID_PLAYER
)
6958 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6962 void Unit::CombatStopWithPets(bool cast
)
6965 if(Pet
* pet
= GetPet())
6966 pet
->CombatStop(cast
);
6967 if(Unit
* charm
= GetCharm())
6968 charm
->CombatStop(cast
);
6969 if(GetTypeId()==TYPEID_PLAYER
)
6971 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6972 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6973 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6974 guardian
->CombatStop(cast
);
6978 bool Unit::isAttackingPlayer() const
6980 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
6983 Pet
* pet
= GetPet();
6984 if(pet
&& pet
->isAttackingPlayer())
6987 Unit
* charmed
= GetCharm();
6988 if(charmed
&& charmed
->isAttackingPlayer())
6991 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
6995 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
6996 if(totem
&& totem
->isAttackingPlayer())
7004 void Unit::RemoveAllAttackers()
7006 while (!m_attackers
.empty())
7008 AttackerSet::iterator iter
= m_attackers
.begin();
7009 if(!(*iter
)->AttackStop())
7011 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
7012 m_attackers
.erase(iter
);
7017 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7021 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7023 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7024 if(GetTypeId() == TYPEID_PLAYER
)
7026 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7027 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7029 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7030 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7031 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7032 if (spellInfo
->CasterAuraState
== flag
)
7033 CastSpell(this, itr
->first
, true, NULL
);
7040 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7042 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7043 Unit::AuraMap
& tAuras
= GetAuras();
7044 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7046 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7047 if (spellProto
->CasterAuraState
== flag
)
7049 // exceptions (applied at state but not removed at state change)
7051 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7066 Unit
*Unit::GetOwner() const
7068 uint64 ownerid
= GetOwnerGUID();
7071 return ObjectAccessor::GetUnit(*this, ownerid
);
7074 Unit
*Unit::GetCharmer() const
7076 if(uint64 charmerid
= GetCharmerGUID())
7077 return ObjectAccessor::GetUnit(*this, charmerid
);
7081 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7083 uint64 guid
= GetCharmerOrOwnerGUID();
7084 if(IS_PLAYER_GUID(guid
))
7085 return ObjectAccessor::GetPlayer(*this, guid
);
7087 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7090 Pet
* Unit::GetPet() const
7092 if(uint64 pet_guid
= GetPetGUID())
7094 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7097 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7098 const_cast<Unit
*>(this)->SetPet(0);
7104 Unit
* Unit::GetCharm() const
7106 if(uint64 charm_guid
= GetCharmGUID())
7108 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7111 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7112 const_cast<Unit
*>(this)->SetCharm(0);
7118 void Unit::SetPet(Pet
* pet
)
7120 SetUInt64Value(UNIT_FIELD_SUMMON
,pet
? pet
->GetGUID() : 0);
7122 // FIXME: hack, speed must be set only at follow
7124 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7125 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
7128 void Unit::SetCharm(Unit
* charmed
)
7130 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7133 void Unit::UnsummonAllTotems()
7135 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7140 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7141 if (OldTotem
&& OldTotem
->isTotem())
7142 ((Totem
*)OldTotem
)->UnSummon();
7146 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7149 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7150 data
.append(pVictim
->GetPackGUID());
7151 data
.append(GetPackGUID());
7152 data
<< uint32(SpellID
);
7153 data
<< uint32(Damage
);
7154 data
<< uint8(critical
? 1 : 0);
7155 data
<< uint8(0); // unused in client?
7156 SendMessageToSet(&data
, true);
7159 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7161 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7162 data
.append(pVictim
->GetPackGUID());
7163 data
.append(GetPackGUID());
7164 data
<< uint32(SpellID
);
7165 data
<< uint32(powertype
);
7166 data
<< uint32(Damage
);
7167 //data << uint8(critical ? 1 : 0); // removed in 2.4.0
7168 SendMessageToSet(&data
, true);
7171 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7173 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7176 int32 BonusDamage
= 0;
7177 if( GetTypeId()==TYPEID_UNIT
)
7179 // Pets just add their bonus damage to their spell damage
7180 // note that their spell damage is just gain of their own auras
7181 if (((Creature
*)this)->isPet())
7183 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7185 // For totems get damage bonus from owner (statue isn't totem in fact)
7186 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7188 if(Unit
* owner
= GetOwner())
7189 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7194 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7196 // Taken/Done fixed damage bonus auras
7197 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7198 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7200 // Damage over Time spells bonus calculation
7201 float DotFactor
= 1.0f
;
7202 if(damagetype
== DOT
)
7204 int32 DotDuration
= GetSpellDuration(spellProto
);
7208 if(DotDuration
> 30000) DotDuration
= 30000;
7209 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7211 for(int j
= 0; j
< 3; j
++)
7213 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7214 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7215 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7222 if(spellProto
->EffectAmplitude
[x
] != 0)
7223 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7226 DoneAdvertisedBenefit
/= DotTicks
;
7227 TakenAdvertisedBenefit
/= DotTicks
;
7232 // Taken/Done total percent damage auras
7233 float DoneTotalMod
= 1.0f
;
7234 float TakenTotalMod
= 1.0f
;
7237 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7238 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7240 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7241 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7242 // -1 == any item class (not wand then)
7243 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7244 // 0 == any inventory type (not wand then)
7246 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7250 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7251 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7252 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7253 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7254 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7257 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7258 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7259 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7260 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7262 // .. taken pct: scripted (increases damage of * against targets *)
7263 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7264 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7266 switch((*i
)->GetModifier()->m_miscvalue
)
7269 case 4920: case 4919:
7270 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7271 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7275 // .. taken pct: dummy auras
7276 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7277 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7279 switch((*i
)->GetSpellProto()->SpellIconID
)
7283 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7285 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7287 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7288 if (mod
< (*i
)->GetModifier()->m_amount
)
7289 mod
= (*i
)->GetModifier()->m_amount
;
7290 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7295 for(int j
=0;j
<3;j
++)
7297 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7299 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7307 // Distribute Damage over multiple effects, reduce by AoE
7308 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7310 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7311 for(int j
= 0; j
< 3; ++j
)
7313 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7314 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7321 switch(spellProto
->SpellFamilyName
)
7323 case SPELLFAMILY_MAGE
:
7324 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7325 if(spellProto
->Id
==12654)
7330 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7332 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7333 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7334 TakenTotalMod
*= 3.0f
;
7336 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7337 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7339 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7340 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7342 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7343 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7346 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7349 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7353 // Arcane Missiles triggered spell
7354 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7358 // Blizzard triggered spell
7359 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7364 case SPELLFAMILY_WARLOCK
:
7366 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7368 CastingTime
= 2800; // 80% from +shadow damage
7369 DoneTotalMod
= 1.0f
;
7370 TakenTotalMod
= 1.0f
;
7373 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7375 CastingTime
= 3360; // 96% from +shadow damage
7376 DoneTotalMod
= 1.0f
;
7377 TakenTotalMod
= 1.0f
;
7379 // Soul Fire - 115% of Fire Damage
7380 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7384 // Curse of Agony - 120% of Shadow Damage
7385 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7389 // Drain Mana - 0% of Shadow Damage
7390 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7394 // Drain Soul 214.3%
7395 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7400 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7402 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7404 // Unstable Affliction - 180%
7405 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7410 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7415 case SPELLFAMILY_PALADIN
:
7416 // Consecration - 95% of Holy Damage
7417 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7422 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7423 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7425 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7426 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7428 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7429 CastingTime
= uint32(wspeed
*3500*0.102f
);
7431 CastingTime
= uint32(wspeed
*3500*0.098f
);
7433 // Judgement of Righteousness - 73%
7434 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7438 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7439 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7444 // Holy shield - 5% of Holy Damage
7445 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7449 // Blessing of Sanctuary - 0%
7450 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7454 // Seal of Righteousness trigger - already computed for parent spell
7455 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7460 case SPELLFAMILY_SHAMAN
:
7462 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7464 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7465 CastingTime
= 749; // ignore CastingTime and use as modifier
7466 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7467 CastingTime
= 280; // ignore CastingTime and use as modifier
7468 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7469 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7471 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7472 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7473 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7475 case SPELLFAMILY_PRIEST
:
7476 // Mana Burn - 0% of Shadow Damage
7477 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7481 // Mind Flay - 59% of Shadow Damage
7482 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7486 // Holy Fire - 86.71%, DoT - 16.5%
7487 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7489 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7490 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7492 // Shadowguard - 28% per charge
7493 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7497 // Touch of Weakeness - 10%
7498 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7502 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7503 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7508 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7513 case SPELLFAMILY_DRUID
:
7514 // Hurricane triggered spell
7515 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7520 case SPELLFAMILY_WARRIOR
:
7521 case SPELLFAMILY_HUNTER
:
7522 case SPELLFAMILY_ROGUE
:
7529 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7531 // Spellmod SpellDamage
7532 float SpellModSpellDamage
= 100.0f
;
7534 if(Player
* modOwner
= GetSpellModOwner())
7535 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7537 SpellModSpellDamage
/= 100.0f
;
7539 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7540 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7542 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7544 // Add flat bonus from spell damage versus
7545 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7547 // apply spellmod to Done damage
7548 if(Player
* modOwner
= GetSpellModOwner())
7549 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7551 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7553 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7554 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7556 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7559 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7561 int32 DoneAdvertisedBenefit
= 0;
7564 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7565 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7566 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7567 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7568 // -1 == any item class (not wand then)
7569 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7570 // 0 == any inventory type (not wand then)
7571 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7573 if (GetTypeId() == TYPEID_PLAYER
)
7575 // Damage bonus from stats
7576 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7577 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7579 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7581 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7582 uint8 eff
= (*i
)->GetEffIndex();
7584 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7585 Stats usedStat
= STAT_INTELLECT
;
7586 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7587 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7589 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7592 // ... and attack power
7593 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7594 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7595 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7596 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7599 return DoneAdvertisedBenefit
;
7602 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7604 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7606 int32 TakenAdvertisedBenefit
= 0;
7607 // ..done (for creature type by mask) in taken
7608 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7609 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7610 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7611 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7614 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7615 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7616 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7617 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7619 return TakenAdvertisedBenefit
;
7622 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7624 // not criting spell
7625 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7628 float crit_chance
= 0.0f
;
7629 switch(spellProto
->DmgClass
)
7631 case SPELL_DAMAGE_CLASS_NONE
:
7633 case SPELL_DAMAGE_CLASS_MAGIC
:
7635 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7637 // For other schools
7638 else if (GetTypeId() == TYPEID_PLAYER
)
7639 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7642 crit_chance
= m_baseSpellCritChance
;
7643 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7646 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7648 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7649 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7650 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7651 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7652 // Modify by player victim resilience
7653 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7654 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7655 // scripted (increase crit chance ... against ... target by x%
7656 if(pVictim
->isFrozen()) // Shatter
7658 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7659 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7661 switch((*i
)->GetModifier()->m_miscvalue
)
7663 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7664 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7665 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7666 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7667 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7674 case SPELL_DAMAGE_CLASS_MELEE
:
7675 case SPELL_DAMAGE_CLASS_RANGED
:
7679 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7680 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7681 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7689 // only players use intelligence for critical chance computations
7690 if(Player
* modOwner
= GetSpellModOwner())
7691 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7693 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7694 if (roll_chance_f(crit_chance
))
7699 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7701 // Calculate critical bonus
7703 switch(spellProto
->DmgClass
)
7705 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7706 case SPELL_DAMAGE_CLASS_RANGED
:
7707 // TODO: write here full calculation for melee/ranged spells
7708 crit_bonus
= damage
;
7711 crit_bonus
= damage
/ 2; // for spells is 50%
7715 // adds additional damage to crit_bonus (from talents)
7716 if(Player
* modOwner
= GetSpellModOwner())
7717 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7721 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7722 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7726 damage
+= crit_bonus
;
7731 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7733 // For totems get healing bonus from owner (statue isn't totem in fact)
7734 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7735 if(Unit
* owner
= GetOwner())
7736 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7740 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7741 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7742 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7743 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7746 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7747 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7750 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7752 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7753 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7755 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7756 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7758 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
7761 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7762 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7764 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7765 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7770 float ActualBenefit
= 0.0f
;
7772 if (AdvertisedBenefit
!= 0)
7774 // Healing over Time spells
7775 float DotFactor
= 1.0f
;
7776 if(damagetype
== DOT
)
7778 int32 DotDuration
= GetSpellDuration(spellProto
);
7782 if(DotDuration
> 30000) DotDuration
= 30000;
7783 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7785 for(int j
= 0; j
< 3; j
++)
7787 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7788 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7789 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7796 if(spellProto
->EffectAmplitude
[x
] != 0)
7797 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7799 AdvertisedBenefit
/= DotTicks
;
7803 // distribute healing to all effects, reduce AoE damage
7804 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7806 // 0% bonus for damage and healing spells for leech spells from healing bonus
7807 for(int j
= 0; j
< 3; ++j
)
7809 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7810 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7818 switch (spellProto
->SpellFamilyName
)
7820 case SPELLFAMILY_SHAMAN
:
7821 // Healing stream from totem (add 6% per tick from hill bonus owner)
7822 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7824 // Earth Shield 30% per charge
7825 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7828 case SPELLFAMILY_DRUID
:
7830 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7832 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7833 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7835 // Tranquility triggered spell
7836 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7839 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7842 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7844 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7845 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7848 case SPELLFAMILY_PRIEST
:
7850 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7853 case SPELLFAMILY_PALADIN
:
7854 // Seal and Judgement of Light
7855 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7858 case SPELLFAMILY_WARRIOR
:
7859 case SPELLFAMILY_ROGUE
:
7860 case SPELLFAMILY_HUNTER
:
7865 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7867 // Spellmod SpellDamage
7868 float SpellModSpellDamage
= 100.0f
;
7870 if(Player
* modOwner
= GetSpellModOwner())
7871 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7873 SpellModSpellDamage
/= 100.0f
;
7875 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7878 // use float as more appropriate for negative values and percent applying
7879 float heal
= healamount
+ ActualBenefit
;
7881 // TODO: check for ALL/SPELLS type
7882 // Healing done percent
7883 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7884 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7885 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7887 // apply spellmod to Done amount
7888 if(Player
* modOwner
= GetSpellModOwner())
7889 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7891 // Healing Wave cast
7892 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7894 // Search for Healing Way on Victim (stack up to 3 time)
7896 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7897 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7898 if((*itr
)->GetId() == 29203)
7899 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7902 heal
= heal
* (100 + pctMod
) / 100;
7905 // Healing taken percent
7906 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7908 heal
*= (100.0f
+ minval
) / 100.0f
;
7910 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7912 heal
*= (100.0f
+ maxval
) / 100.0f
;
7914 if (heal
< 0) heal
= 0;
7916 return uint32(heal
);
7919 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7921 int32 AdvertisedBenefit
= 0;
7923 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7924 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7925 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7926 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7928 // Healing bonus of spirit, intellect and strength
7929 if (GetTypeId() == TYPEID_PLAYER
)
7931 // Healing bonus from stats
7932 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7933 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7935 // stat used dependent from misc value (stat index)
7936 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7937 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7940 // ... and attack power
7941 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7942 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7943 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7944 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7946 return AdvertisedBenefit
;
7949 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7951 int32 AdvertisedBenefit
= 0;
7952 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7953 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7954 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7955 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7956 return AdvertisedBenefit
;
7959 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7961 // no charges dependent checks
7962 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7963 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7964 if(itr
->type
& shoolMask
)
7967 // charges dependent checks
7968 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7969 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7971 if(itr
->type
& shoolMask
)
7975 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7976 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
7978 if((*auraItr
)->GetId()==itr
->spellId
)
7980 if((*auraItr
)->m_procCharges
> 0)
7982 --(*auraItr
)->m_procCharges
;
7983 if((*auraItr
)->m_procCharges
==0)
7984 RemoveAurasDueToSpell(itr
->spellId
);
7997 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8004 //FIX ME this hack: don't get feared if stunned
8005 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8007 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8011 // not have spells with charges currently
8012 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8013 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8014 if(itr
->type
== spellInfo
->Dispel
)
8017 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
) && // unaffected by school immunity
8018 !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)) // can remove immune (by dispell or immune it)
8020 // not have spells with charges currently
8021 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8022 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8023 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8024 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8028 // charges dependent checks
8030 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8031 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8033 if(itr
->type
== spellInfo
->Mechanic
)
8037 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8038 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8040 if((*auraItr
)->GetId()==itr
->spellId
)
8042 if((*auraItr
)->m_procCharges
> 0)
8044 --(*auraItr
)->m_procCharges
;
8045 if((*auraItr
)->m_procCharges
==0)
8046 RemoveAurasDueToSpell(itr
->spellId
);
8059 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8061 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8062 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8063 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8064 if(itr
->type
== effect
)
8067 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8068 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8069 if(itr
->type
== mechanic
)
8075 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8080 uint32 family
= spellInfo
->SpellFamilyName
;
8081 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8083 if((family
== 5 && flags
== 256) || //Searing Pain
8084 (family
== 6 && flags
== 8192) || //Mind Blast
8085 (family
== 11 && flags
== 1048576)) //Earth Shock
8091 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8099 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8101 // Taken/Done fixed damage bonus auras
8102 int32 DoneFlatBenefit
= 0;
8103 int32 TakenFlatBenefit
= 0;
8105 // ..done (for creature type by mask) in taken
8106 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8107 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8108 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8109 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8112 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8114 // ..done (base at attack power for marked target and base at attack power for creature type)
8116 if(attType
== RANGED_ATTACK
)
8118 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8120 // ..done (base at attack power and creature type)
8121 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8122 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8123 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8124 APbonus
+= (*i
)->GetModifier()->m_amount
;
8128 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8130 // ..done (base at attack power and creature type)
8131 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8132 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8133 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8134 APbonus
+= (*i
)->GetModifier()->m_amount
;
8137 if (APbonus
!=0) // Can be negative
8139 bool normalized
= false;
8142 for (uint8 i
= 0; i
<3;i
++)
8144 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8152 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8156 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8157 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8158 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8159 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8161 if(attType
!=RANGED_ATTACK
)
8162 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8164 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8166 // Done/Taken total percent damage auras
8167 float DoneTotalMod
= 1;
8168 float TakenTotalMod
= 1;
8171 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8172 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8174 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8175 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8176 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8177 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8180 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8181 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8182 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8183 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8185 // .. taken pct: dummy auras
8186 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8187 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8189 switch((*i
)->GetSpellProto()->SpellIconID
)
8193 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8195 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8197 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8198 if (mod
< (*i
)->GetModifier()->m_amount
)
8199 mod
= (*i
)->GetModifier()->m_amount
;
8200 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8205 if(spellProto
==NULL
)
8207 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8208 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8209 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8214 // .. taken pct: class scripts
8215 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8216 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8218 switch((*i
)->GetMiscValue())
8220 case 6427: case 6428: // Dirty Deeds
8221 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8223 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8224 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8226 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8230 // effect 0 have expected value but in negative state
8231 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8237 if(attType
!= RANGED_ATTACK
)
8239 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8240 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8241 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8245 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8246 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8247 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8250 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8252 // apply spellmod to Done damage
8255 if(Player
* modOwner
= GetSpellModOwner())
8256 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8259 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8261 // bonus result can be negative
8262 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8265 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8269 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8272 if(itr
->type
== type
)
8274 m_spellImmune
[op
].erase(itr
);
8275 next
= m_spellImmune
[op
].begin();
8279 Immune
.spellId
= spellId
;
8281 m_spellImmune
[op
].push_back(Immune
);
8285 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8287 if(itr
->spellId
== spellId
)
8289 m_spellImmune
[op
].erase(itr
);
8297 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8299 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8301 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8302 RemoveAurasWithDispelType(type
);
8305 float Unit::GetWeaponProcChance() const
8307 // normalized proc chance for weapon attack speed
8309 if(isAttackReady(BASE_ATTACK
))
8310 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8311 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8312 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8316 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8318 // proc per minute chance calculation
8319 if (PPM
<= 0) return 0.0f
;
8320 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8324 void Unit::Mount(uint32 mount
)
8329 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8331 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8333 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8336 if(GetTypeId() == TYPEID_PLAYER
)
8338 Pet
* pet
= GetPet();
8341 if(pet
->isControlled())
8343 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8344 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8347 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8350 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8354 void Unit::Unmount()
8359 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8361 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8362 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8364 // only resummon old pet if the player is already added to a map
8365 // this prevents adding a pet to a not created map which would otherwise cause a crash
8366 // (it could probably happen when logging in after a previous crash)
8367 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8369 Pet
* NewPet
= new Pet
;
8370 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8373 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8377 void Unit::SetInCombatWith(Unit
* enemy
)
8379 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8382 SetInCombatState(true);
8387 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8389 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8390 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8392 SetInCombatState(true);
8396 SetInCombatState(false);
8399 void Unit::SetInCombatState(bool PvP
)
8401 // only alive units can be in combat
8406 m_CombatTimer
= 5000;
8407 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8409 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8410 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8413 void Unit::ClearInCombat()
8416 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8418 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8419 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8421 // Player's state will be cleared in Player::UpdateContestedPvP
8422 if(GetTypeId()!=TYPEID_PLAYER
)
8423 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8426 bool Unit::isTargetableForAttack() const
8428 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8431 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8434 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8437 int32
Unit::ModifyHealth(int32 dVal
)
8444 int32 curHealth
= (int32
)GetHealth();
8446 int32 val
= dVal
+ curHealth
;
8453 int32 maxHealth
= (int32
)GetMaxHealth();
8458 gain
= val
- curHealth
;
8460 else if(curHealth
!= maxHealth
)
8462 SetHealth(maxHealth
);
8463 gain
= maxHealth
- curHealth
;
8469 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8476 int32 curPower
= (int32
)GetPower(power
);
8478 int32 val
= dVal
+ curPower
;
8485 int32 maxPower
= (int32
)GetMaxPower(power
);
8489 SetPower(power
,val
);
8490 gain
= val
- curPower
;
8492 else if(curPower
!= maxPower
)
8494 SetPower(power
,maxPower
);
8495 gain
= maxPower
- curPower
;
8501 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
, bool is3dDistance
) const
8506 // Always can see self
8510 // player visible for other player if not logout and at same transport
8511 // including case when player is out of world
8512 bool at_same_transport
=
8513 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8514 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8515 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8516 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8519 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8522 // forbidden to seen (at GM respawn command)
8523 if(m_Visibility
==VISIBILITY_RESPAWN
)
8526 // always seen by owner
8527 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8530 // Grid dead/alive checks
8531 if( u
->GetTypeId()==TYPEID_PLAYER
)
8533 // non visible at grid for any stealth state
8534 if(!IsVisibleInGridForPlayer((Player
*)u
))
8537 // if player is dead then he can't detect anyone in any cases
8543 // all dead creatures/players not visible for any creatures
8544 if(!u
->isAlive() || !isAlive())
8548 // different visible distance checks
8549 if(u
->isInFlight()) // what see player in flight
8551 // use object grey distance for all (only see objects any way)
8552 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8555 else if(!isAlive()) // distance for show body
8557 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8560 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8562 if(u
->GetTypeId()==TYPEID_PLAYER
)
8564 // Players far than max visible distance for player or not in our map are not visible too
8565 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8570 // Units far than max visible distance for creature or not in our map are not visible too
8571 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8575 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8577 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8578 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8581 else // distance for show creature
8583 // Units far than max visible distance for creature or not in our map are not visible too
8584 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8588 // Visible units, always are visible for all units, except for units under invisibility
8589 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8592 // GMs see any players, not higher GMs and all units
8593 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8595 if(GetTypeId() == TYPEID_PLAYER
)
8596 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8601 // non faction visibility non-breakable for non-GMs
8602 if (m_Visibility
== VISIBILITY_OFF
)
8606 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8608 // detectable invisibility case
8610 // Invisible units, always are visible for units under same invisibility type
8611 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8612 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8613 u
->canDetectInvisibilityOf(this) ||
8614 // Units that can detect invisibility always are visible for units that can be detected
8615 canDetectInvisibilityOf(u
) ))
8620 // special cases for always overwrite invisibility/stealth
8621 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8624 if (!u
->IsHostileTo(this))
8626 // 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)
8627 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8629 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8632 // else apply same rules as for hostile case (detecting check for stealth)
8638 // Hunter mark functionality
8639 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8640 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8641 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8644 // else apply detecting check for stealth
8647 // none other cases for detect invisibility, so invisible
8651 // else apply stealth detecting check
8654 // unit got in stealth in this moment and must ignore old detected state
8655 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8658 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8659 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8662 // NOW ONLY STEALTH CASE
8664 // stealth and detected and visible for some seconds
8665 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8668 //if in non-detect mode then invisible for unit
8674 // If is attacked then stealth is lost, some creature can use stealth too
8675 if( !getAttackers().empty() )
8678 // If there is collision rogue is seen regardless of level difference
8679 // TODO: check sizes in DB
8680 float distance
= GetDistance(u
);
8681 if (distance
< 0.24f
)
8684 //If a mob or player is stunned he will not be able to detect stealth
8685 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8688 // Creature can detect target only in aggro radius
8689 if(u
->GetTypeId() != TYPEID_PLAYER
)
8691 //Always invisible from back and out of aggro range
8692 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8698 //Always invisible from back
8699 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8704 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8705 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8707 //Calculation if target is in front
8709 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8710 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8712 //Visible distance is modified by
8713 //-Level Diff (every level diff = 1.0f in visible distance)
8714 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8716 //This allows to check talent tree and will add addition stealth dependent on used points)
8717 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8721 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8722 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8723 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8725 if(distance
> visibleDistance
)
8729 // Now check is target visible with LoS
8731 u
->GetPosition(ox
,oy
,oz
);
8732 return IsWithinLOS(ox
,oy
,oz
);
8735 void Unit::SetVisibility(UnitVisibility x
)
8743 if(GetTypeId()==TYPEID_PLAYER
)
8744 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8746 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8750 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8752 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8754 for(uint32 i
= 0; i
< 10; ++i
)
8756 if(((1 << i
) & mask
)==0)
8759 // find invisibility level
8760 uint32 invLevel
= 0;
8761 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8762 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8763 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8764 invLevel
= (*itr
)->GetModifier()->m_amount
;
8766 // find invisibility detect level
8767 uint32 detectLevel
= 0;
8768 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8769 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8770 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8771 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8773 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8775 detectLevel
= ((Player
*)this)->GetDrunkValue();
8778 if(invLevel
<= detectLevel
)
8786 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8788 int32 main_speed_mod
= 0;
8789 float stack_bonus
= 1.0f
;
8790 float non_stack_bonus
= 1.0f
;
8798 if (IsMounted()) // Use on mount auras
8800 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8801 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8802 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8806 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8807 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8808 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8816 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8823 if (IsMounted()) // Use on mount auras
8824 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8825 else // Use not mount (shapeshift for example) auras (should stack)
8826 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8827 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8828 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8834 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8838 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8839 // now we ready for speed calculation
8840 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8848 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8849 // TODO: possible affect only on MOVE_RUN
8850 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8852 // Use speed from aura
8853 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8854 if (speed
> max_speed
)
8863 // Apply strongest slow aura mod to speed
8864 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8866 speed
*=(100.0f
+ slow
)/100.0f
;
8867 SetSpeed(mtype
, speed
, forced
);
8870 float Unit::GetSpeed( UnitMoveType mtype
) const
8872 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8875 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8880 // Update speed only on change
8881 if (m_speed_rate
[mtype
] == rate
)
8884 m_speed_rate
[mtype
] = rate
;
8886 propagateSpeedChange();
8888 // Send speed change packet only for player
8889 if (GetTypeId()!=TYPEID_PLAYER
)
8898 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8901 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8904 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8907 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8910 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8913 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8916 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8919 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8922 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8926 data
.append(GetPackGUID());
8927 data
<< uint32(0); //movement flags
8928 data
<< uint8(0); //unk
8929 data
<< uint32(getMSTime());
8930 data
<< float(GetPositionX());
8931 data
<< float(GetPositionY());
8932 data
<< float(GetPositionZ());
8933 data
<< float(GetOrientation());
8934 data
<< uint32(0); //flag unk
8935 data
<< float(GetSpeed(mtype
));
8936 SendMessageToSet( &data
, true );
8940 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8941 // and do it only for real sent packets and use run for run/mounted as client expected
8942 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8946 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8949 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8952 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8955 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8958 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8961 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8964 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8967 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8970 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8973 data
.append(GetPackGUID());
8975 if (mtype
== MOVE_RUN
)
8976 data
<< uint8(0); // new 2.1.0
8977 data
<< float(GetSpeed(mtype
));
8978 SendMessageToSet( &data
, true );
8980 if(Pet
* pet
= GetPet())
8981 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
8984 void Unit::SetHover(bool on
)
8987 CastSpell(this,11010,true);
8989 RemoveAurasDueToSpell(11010);
8992 void Unit::setDeathState(DeathState s
)
8994 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
8998 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9000 if(IsNonMeleeSpellCasted(false))
9001 InterruptNonMeleeSpells(false);
9006 RemoveAllAurasOnDeath();
9007 UnsummonAllTotems();
9009 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9010 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9011 // remove aurastates allowing special moves
9012 ClearAllReactives();
9013 ClearDiminishings();
9015 else if(s
== JUST_ALIVED
)
9017 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9020 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9022 //_ApplyAllAuraMods();
9027 /*########################################
9029 ######## AGGRO SYSTEM ########
9031 ########################################*/
9032 bool Unit::CanHaveThreatList() const
9034 // only creatures can have threat list
9035 if( GetTypeId() != TYPEID_UNIT
)
9038 // only alive units can have threat list
9042 // pets and totems can not have threat list
9043 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() )
9049 //======================================================================
9051 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9053 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9056 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9058 return threat
* m_threatModifier
[school
];
9061 //======================================================================
9063 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9065 // Only mobs can manage threat lists
9066 if(CanHaveThreatList())
9067 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9070 //======================================================================
9072 void Unit::DeleteThreatList()
9074 m_ThreatManager
.clearReferences();
9077 //======================================================================
9079 void Unit::TauntApply(Unit
* taunter
)
9081 assert(GetTypeId()== TYPEID_UNIT
);
9083 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9086 if(!CanHaveThreatList())
9089 Unit
*target
= getVictim();
9090 if(target
&& target
== taunter
)
9093 SetInFront(taunter
);
9094 if (((Creature
*)this)->AI())
9095 ((Creature
*)this)->AI()->AttackStart(taunter
);
9097 m_ThreatManager
.tauntApply(taunter
);
9100 //======================================================================
9102 void Unit::TauntFadeOut(Unit
*taunter
)
9104 assert(GetTypeId()== TYPEID_UNIT
);
9106 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9109 if(!CanHaveThreatList())
9112 Unit
*target
= getVictim();
9113 if(!target
|| target
!= taunter
)
9116 if(m_ThreatManager
.isThreatListEmpty())
9118 if(((Creature
*)this)->AI())
9119 ((Creature
*)this)->AI()->EnterEvadeMode();
9123 m_ThreatManager
.tauntFadeOut(taunter
);
9124 target
= m_ThreatManager
.getHostilTarget();
9126 if (target
&& target
!= taunter
)
9129 if (((Creature
*)this)->AI())
9130 ((Creature
*)this)->AI()->AttackStart(target
);
9134 //======================================================================
9136 bool Unit::SelectHostilTarget()
9138 //function provides main threat functionality
9139 //next-victim-selection algorithm and evade mode are called
9140 //threat list sorting etc.
9142 assert(GetTypeId()== TYPEID_UNIT
);
9143 Unit
* target
= NULL
;
9145 //This function only useful once AI has been initialized
9146 if (!((Creature
*)this)->AI())
9149 if(!m_ThreatManager
.isThreatListEmpty())
9151 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9153 target
= m_ThreatManager
.getHostilTarget();
9159 if(!hasUnitState(UNIT_STAT_STUNNED
))
9161 ((Creature
*)this)->AI()->AttackStart(target
);
9165 // no target but something prevent go to evade mode
9166 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9169 // last case when creature don't must go to evade mode:
9170 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9171 // for example at owner command to pet attack some far away creature
9172 // Note: creature not have targeted movement generator but have attacker in this case
9173 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9175 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9177 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9182 // enter in evade mode in other case
9183 ((Creature
*)this)->AI()->EnterEvadeMode();
9188 //======================================================================
9189 //======================================================================
9190 //======================================================================
9192 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9194 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9196 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9198 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9199 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9200 level
= spellProto
->maxLevel
;
9202 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9203 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9204 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9205 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9206 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9208 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9209 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9210 int32 value
= basePoints
+ randvalue
;
9212 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9213 value
+= (int32
)(comboDamage
* comboPoints
);
9215 if(Player
* modOwner
= GetSpellModOwner())
9217 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9218 switch(effect_index
)
9221 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9224 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9227 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9232 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9233 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9234 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9235 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9240 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9242 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9244 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9246 int32 minduration
= GetSpellDuration(spellProto
);
9247 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9251 if( minduration
!= -1 && minduration
!= maxduration
)
9252 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9254 duration
= minduration
;
9258 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9259 // Find total mod value (negative bonus)
9260 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9261 // Find max mod (negative bonus)
9262 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9264 int32 durationMod
= 0;
9265 // Select strongest negative mod
9266 if (durationMod_always
> durationMod_not_stack
)
9267 durationMod
= durationMod_not_stack
;
9269 durationMod
= durationMod_always
;
9271 if (durationMod
!= 0)
9272 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9274 if (duration
< 0) duration
= 0;
9280 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9282 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9284 if(i
->DRGroup
!= group
)
9288 return DIMINISHING_LEVEL_1
;
9291 return DIMINISHING_LEVEL_1
;
9293 // If last spell was casted more than 15 seconds ago - reset the count.
9294 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9296 i
->hitCount
= DIMINISHING_LEVEL_1
;
9297 return DIMINISHING_LEVEL_1
;
9299 // or else increase the count.
9302 return DiminishingLevels(i
->hitCount
);
9305 return DIMINISHING_LEVEL_1
;
9308 void Unit::IncrDiminishing(DiminishingGroup group
)
9310 // Checking for existing in the table
9311 bool IsExist
= false;
9312 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9314 if(i
->DRGroup
!= group
)
9318 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9325 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9328 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9330 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9333 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9334 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9336 // test pet/charm masters instead pets/charmeds
9337 Unit
const* targetOwner
= GetCharmerOrOwner();
9338 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9340 Unit
const* target
= targetOwner
? targetOwner
: this;
9341 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9343 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9349 // Some diminishings applies to mobs too (for example, Stun)
9350 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9352 DiminishingLevels diminish
= Level
;
9355 case DIMINISHING_LEVEL_1
: break;
9356 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9357 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9358 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9363 duration
= int32(duration
* mod
);
9366 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9368 // Checking for existing in the table
9369 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9371 if(i
->DRGroup
!= group
)
9374 i
->hitTime
= getMSTime();
9385 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9387 return ObjectAccessor::GetUnit(object
,guid
);
9390 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9392 return isVisibleForOrDetect(u
, false, inVisibleList
, false);
9395 uint32
Unit::GetCreatureType() const
9397 if(GetTypeId() == TYPEID_PLAYER
)
9399 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9400 if(ssEntry
&& ssEntry
->creatureType
> 0)
9401 return ssEntry
->creatureType
;
9403 return CREATURE_TYPE_HUMANOID
;
9406 return ((Creature
*)this)->GetCreatureInfo()->type
;
9409 /*#######################################
9411 ######## STAT SYSTEM ########
9413 #######################################*/
9415 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9417 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9419 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9425 switch(modifierType
)
9429 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9433 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9436 val
= (100.0f
+ amount
) / 100.0f
;
9437 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9444 if(!CanModifyStats())
9449 case UNIT_MOD_STAT_STRENGTH
:
9450 case UNIT_MOD_STAT_AGILITY
:
9451 case UNIT_MOD_STAT_STAMINA
:
9452 case UNIT_MOD_STAT_INTELLECT
:
9453 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9455 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9456 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9460 case UNIT_MOD_FOCUS
:
9461 case UNIT_MOD_ENERGY
:
9462 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9464 case UNIT_MOD_RESISTANCE_HOLY
:
9465 case UNIT_MOD_RESISTANCE_FIRE
:
9466 case UNIT_MOD_RESISTANCE_NATURE
:
9467 case UNIT_MOD_RESISTANCE_FROST
:
9468 case UNIT_MOD_RESISTANCE_SHADOW
:
9469 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9471 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9472 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9474 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9475 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9476 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9485 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9487 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9489 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9493 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9496 return m_auraModifiersGroup
[unitMod
][modifierType
];
9499 float Unit::GetTotalStatValue(Stats stat
) const
9501 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9503 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9506 // value = ((base_value * base_pct) + total_value) * total_pct
9507 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9508 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9509 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9510 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9515 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9517 if(unitMod
>= UNIT_MOD_END
)
9519 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9523 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9526 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9527 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9528 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9529 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9534 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9536 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9540 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9541 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9542 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9543 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9544 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9545 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9554 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9556 Stats stat
= STAT_STRENGTH
;
9560 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9561 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9562 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9563 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9564 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9573 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9575 Powers power
= POWER_MANA
;
9579 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9580 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9581 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9582 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9583 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9592 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9594 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9596 float val
= GetTotalAuraModValue(unitMod
);
9603 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9605 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9608 return m_weaponDamage
[attType
][type
];
9611 void Unit::SetLevel(uint32 lvl
)
9613 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9616 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9617 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9620 void Unit::SetHealth(uint32 val
)
9622 uint32 maxHealth
= GetMaxHealth();
9626 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9629 if(GetTypeId() == TYPEID_PLAYER
)
9631 if(((Player
*)this)->GetGroup())
9632 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9634 else if(((Creature
*)this)->isPet())
9636 Pet
*pet
= ((Pet
*)this);
9637 if(pet
->isControlled())
9639 Unit
*owner
= GetOwner();
9640 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9641 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9646 void Unit::SetMaxHealth(uint32 val
)
9648 uint32 health
= GetHealth();
9649 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9652 if(GetTypeId() == TYPEID_PLAYER
)
9654 if(((Player
*)this)->GetGroup())
9655 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9657 else if(((Creature
*)this)->isPet())
9659 Pet
*pet
= ((Pet
*)this);
9660 if(pet
->isControlled())
9662 Unit
*owner
= GetOwner();
9663 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9664 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9672 void Unit::SetPower(Powers power
, uint32 val
)
9674 if(GetPower(power
) == val
)
9677 uint32 maxPower
= GetMaxPower(power
);
9681 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9684 if(GetTypeId() == TYPEID_PLAYER
)
9686 if(((Player
*)this)->GetGroup())
9687 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9689 else if(((Creature
*)this)->isPet())
9691 Pet
*pet
= ((Pet
*)this);
9692 if(pet
->isControlled())
9694 Unit
*owner
= GetOwner();
9695 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9696 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9699 // Update the pet's character sheet with happiness damage bonus
9700 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9702 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9707 void Unit::SetMaxPower(Powers power
, uint32 val
)
9709 uint32 cur_power
= GetPower(power
);
9710 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9713 if(GetTypeId() == TYPEID_PLAYER
)
9715 if(((Player
*)this)->GetGroup())
9716 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9718 else if(((Creature
*)this)->isPet())
9720 Pet
*pet
= ((Pet
*)this);
9721 if(pet
->isControlled())
9723 Unit
*owner
= GetOwner();
9724 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9725 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9730 SetPower(power
, val
);
9733 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9735 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9738 if(GetTypeId() == TYPEID_PLAYER
)
9740 if(((Player
*)this)->GetGroup())
9741 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_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_CUR_POWER
);
9755 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9757 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9760 if(GetTypeId() == TYPEID_PLAYER
)
9762 if(((Player
*)this)->GetGroup())
9763 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9765 else if(((Creature
*)this)->isPet())
9767 Pet
*pet
= ((Pet
*)this);
9768 if(pet
->isControlled())
9770 Unit
*owner
= GetOwner();
9771 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9772 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9777 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9779 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9781 tAuraProcTriggerDamage
.push_back(aura
);
9783 tAuraProcTriggerDamage
.remove(aura
);
9786 uint32
Unit::GetCreatePowers( Powers power
) const
9788 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9791 case POWER_MANA
: return GetCreateMana();
9792 case POWER_RAGE
: return 1000;
9793 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9794 case POWER_ENERGY
: return 100;
9795 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9801 void Unit::AddToWorld()
9803 Object::AddToWorld();
9806 void Unit::RemoveFromWorld()
9811 RemoveNotOwnSingleTargetAuras();
9814 Object::RemoveFromWorld();
9817 void Unit::CleanupsBeforeDelete()
9819 if(m_uint32Values
) // only for fully created object
9821 InterruptNonMeleeSpells(true);
9822 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9824 ClearComboPointHolders();
9826 getHostilRefManager().setOnlineOfflineState(false);
9828 RemoveAllGameObjects();
9829 RemoveAllDynObjects();
9830 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9835 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9838 m_charmInfo
= new CharmInfo(charm
);
9842 CharmInfo::CharmInfo(Unit
* unit
)
9843 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9845 for(int i
=0; i
<4; ++i
)
9847 m_charmspells
[i
].spellId
= 0;
9848 m_charmspells
[i
].active
= ACT_DISABLED
;
9852 void CharmInfo::InitPetActionBar()
9854 // the first 3 SpellOrActions are attack, follow and stay
9855 for(uint32 i
= 0; i
< 3; i
++)
9857 PetActionBar
[i
].Type
= ACT_COMMAND
;
9858 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9860 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9861 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9863 for(uint32 i
=0; i
< 4; i
++)
9865 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9866 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9870 void CharmInfo::InitEmptyActionBar()
9872 for(uint32 x
= 1; x
< 10; ++x
)
9874 PetActionBar
[x
].Type
= ACT_CAST
;
9875 PetActionBar
[x
].SpellOrAction
= 0;
9877 PetActionBar
[0].Type
= ACT_COMMAND
;
9878 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9881 void CharmInfo::InitPossessCreateSpells()
9883 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9886 InitEmptyActionBar(); //charm action bar
9888 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9890 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9891 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9893 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9897 void CharmInfo::InitCharmCreateSpells()
9899 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9901 InitEmptyActionBar();
9907 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9909 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9910 m_charmspells
[x
].spellId
= spellId
;
9915 if (IsPassiveSpell(spellId
))
9917 m_unit
->CastSpell(m_unit
, spellId
, true);
9918 m_charmspells
[x
].active
= ACT_PASSIVE
;
9922 ActiveStates newstate
;
9923 bool onlyselfcast
= true;
9924 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9926 if(!spellInfo
) onlyselfcast
= false;
9927 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9929 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9930 onlyselfcast
= false;
9933 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9934 newstate
= ACT_DISABLED
;
9936 newstate
= ACT_CAST
;
9938 AddSpellToAB(0, spellId
, newstate
);
9943 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9945 for(uint8 i
= 0; i
< 10; i
++)
9947 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9949 PetActionBar
[i
].SpellOrAction
= newid
;
9952 if(newstate
== ACT_DECIDE
)
9953 PetActionBar
[i
].Type
= ACT_DISABLED
;
9955 PetActionBar
[i
].Type
= newstate
;
9964 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9966 if(IsPassiveSpell(spellid
))
9969 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9971 if(spellid
== m_charmspells
[x
].spellId
)
9973 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
9978 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
9980 m_petnumber
= petnumber
;
9982 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
9984 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
9987 bool Unit::isFrozen() const
9989 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
9990 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
9991 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
9996 struct ProcTriggeredData
9998 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
9999 : triggeredByAura(_triggeredByAura
),
10000 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10001 cooldown(_cooldown
)
10004 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10005 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10006 uint32 cooldown
; // possible hidden cooldown
10009 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10011 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10013 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10015 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10016 ProcTriggeredList procTriggered
;
10018 AuraList
const& auras
= GetAurasByType(*aur
);
10019 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10025 uint32 cooldown
; // returned at next line
10026 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10029 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10032 // Handle effects proceed this time
10033 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10035 // Some auras can be deleted in function called in this loop (except first, ofc)
10036 // Until storing auras in std::multimap to hard check deleting by another way
10037 if(i
!= procTriggered
.begin())
10039 bool found
= false;
10040 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10041 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10042 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10044 if(itr
->second
==i
->triggeredByAura
)
10053 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
);
10054 sLog
.outError("It can be deleted one from early processed auras:");
10055 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10056 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10057 sLog
.outError(" <end of list>");
10062 /// this is aura triggering code call
10063 Aura
* triggeredByAura
= i
->triggeredByAura
;
10065 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10066 /// used in speedup code check before check aura existance.
10067 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10069 /// success in event proccesing
10070 /// used in speedup code check before check aura existance.
10071 bool casted
= false;
10073 /// process triggered code
10076 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10078 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10079 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10080 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10083 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10085 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10086 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10087 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10088 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10092 case SPELL_AURA_DUMMY
:
10094 uint32 effect
= triggeredByAura
->GetEffIndex();
10095 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10096 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10097 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10100 case SPELL_AURA_PRAYER_OF_MENDING
:
10102 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10103 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10105 casted
= HandleMeandingAuraProc(triggeredByAura
);
10108 case SPELL_AURA_MOD_HASTE
:
10110 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10111 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10112 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10115 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10117 // nothing do, just charges counter
10118 // but count only in case appropriate school damage
10119 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10122 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10124 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10125 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10126 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10131 // nothing do, just charges counter
10137 /// Update charge (aura can be removed by triggers)
10138 if(casted
&& triggeredByAuraWithCharges
)
10140 /// need re-found aura (can be dropped by triggers)
10141 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10142 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10143 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10145 if(itr
->second
== triggeredByAura
) // pointer still valid
10147 if(triggeredByAura
->m_procCharges
> 0)
10148 triggeredByAura
->m_procCharges
-= 1;
10150 triggeredByAura
->UpdateAuraCharges();
10157 /// Safely remove auras with zero charges
10158 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10161 if((*i
)->m_procCharges
== 0)
10163 RemoveAurasDueToSpell((*i
)->GetId());
10164 next
= auras
.begin();
10170 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10172 return SPELL_SCHOOL_MASK_NORMAL
;
10175 Player
* Unit::GetSpellModOwner()
10177 if(GetTypeId()==TYPEID_PLAYER
)
10178 return (Player
*)this;
10179 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10181 Unit
* owner
= GetOwner();
10182 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10183 return (Player
*)owner
;
10188 ///----------Pet responses methods-----------------
10189 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10191 Unit
*owner
= GetCharmerOrOwner();
10192 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10195 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10196 data
<< uint32(spellid
);
10197 data
<< uint8(msg
);
10198 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10201 void Unit::SendPetActionFeedback (uint8 msg
)
10203 Unit
* owner
= GetOwner();
10204 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10207 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10208 data
<< uint8(msg
);
10209 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10212 void Unit::SendPetTalk (uint32 pettalk
)
10214 Unit
* owner
= GetOwner();
10215 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10218 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10219 data
<< uint64(GetGUID());
10220 data
<< uint32(pettalk
);
10221 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10224 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10226 Unit
* owner
= GetOwner();
10227 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10230 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10231 data
<< uint64(GetGUID());
10232 data
<< uint8(0x0); // flags (0x1, 0x2)
10233 data
<< uint32(spellid
);
10234 data
<< uint32(cooltime
);
10236 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10239 void Unit::SendPetClearCooldown (uint32 spellid
)
10241 Unit
* owner
= GetOwner();
10242 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10245 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10246 data
<< uint32(spellid
);
10247 data
<< uint64(GetGUID());
10248 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10251 void Unit::SendPetAIReaction(uint64 guid
)
10253 Unit
* owner
= GetOwner();
10254 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10257 WorldPacket
data(SMSG_AI_REACTION
, 12);
10258 data
<< uint64(guid
) << uint32(00000002);
10259 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10262 ///----------End of Pet responses methods----------
10264 void Unit::StopMoving()
10266 clearUnitState(UNIT_STAT_MOVING
);
10268 // send explicit stop packet
10269 // rely on vmaps here because for example stormwind is in air
10270 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10271 //if (fabs(GetPositionZ() - z) < 2.0f)
10272 // Relocate(GetPositionX(), GetPositionY(), z);
10273 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10275 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10277 // update position and orientation;
10279 BuildHeartBeatMsg(&data
);
10280 SendMessageToSet(&data
,false);
10283 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10287 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10290 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10292 GetMotionMaster()->MovementExpired(false);
10293 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10295 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10297 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10301 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10303 GetMotionMaster()->MovementExpired(false);
10305 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10307 // restore appropriate movement generator
10309 GetMotionMaster()->MoveChase(getVictim());
10311 GetMotionMaster()->Initialize();
10313 // attack caster if can
10314 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10315 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10316 ((Creature
*)this)->AI()->AttackStart(caster
);
10320 if (GetTypeId() == TYPEID_PLAYER
)
10321 ((Player
*)this)->SetClientControl(this, !apply
);
10324 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10328 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10330 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10332 GetMotionMaster()->MoveConfused();
10336 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10338 GetMotionMaster()->MovementExpired(false);
10340 if (GetTypeId() == TYPEID_UNIT
)
10342 // if in combat restore movement generator
10344 GetMotionMaster()->MoveChase(getVictim());
10348 if(GetTypeId() == TYPEID_PLAYER
)
10349 ((Player
*)this)->SetClientControl(this, !apply
);
10352 bool Unit::IsSitState() const
10354 uint8 s
= getStandState();
10355 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10356 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10357 s
== PLAYER_STATE_SIT
;
10360 bool Unit::IsStandState() const
10362 uint8 s
= getStandState();
10363 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10366 void Unit::SetStandState(uint8 state
)
10368 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10370 if (IsStandState())
10371 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10373 if(GetTypeId()==TYPEID_PLAYER
)
10375 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10376 data
<< (uint8
)state
;
10377 ((Player
*)this)->GetSession()->SendPacket(&data
);
10381 bool Unit::IsPolymorphed() const
10383 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10386 void Unit::SetDisplayId(uint32 modelId
)
10388 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10390 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10392 Pet
*pet
= ((Pet
*)this);
10393 if(!pet
->isControlled())
10395 Unit
*owner
= GetOwner();
10396 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10397 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10401 void Unit::ClearComboPointHolders()
10403 while(!m_ComboPointHolders
.empty())
10405 uint32 lowguid
= *m_ComboPointHolders
.begin();
10407 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10408 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10409 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10411 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10415 void Unit::ClearAllReactives()
10418 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10419 m_reactiveTimer
[i
] = 0;
10421 if (HasAuraState( AURA_STATE_DEFENSE
))
10422 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10423 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10424 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10425 if (HasAuraState( AURA_STATE_CRIT
))
10426 ModifyAuraState(AURA_STATE_CRIT
, false);
10427 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10428 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10430 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10431 ((Player
*)this)->ClearComboPoints();
10434 void Unit::UpdateReactives( uint32 p_time
)
10436 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10438 ReactiveType reactive
= ReactiveType(i
);
10440 if(!m_reactiveTimer
[reactive
])
10443 if ( m_reactiveTimer
[reactive
] <= p_time
)
10445 m_reactiveTimer
[reactive
] = 0;
10447 switch ( reactive
)
10449 case REACTIVE_DEFENSE
:
10450 if (HasAuraState(AURA_STATE_DEFENSE
))
10451 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10453 case REACTIVE_HUNTER_PARRY
:
10454 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10455 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10457 case REACTIVE_CRIT
:
10458 if (HasAuraState(AURA_STATE_CRIT
))
10459 ModifyAuraState(AURA_STATE_CRIT
, false);
10461 case REACTIVE_HUNTER_CRIT
:
10462 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10463 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10465 case REACTIVE_OVERPOWER
:
10466 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10467 ((Player
*)this)->ClearComboPoints();
10475 m_reactiveTimer
[reactive
] -= p_time
;
10480 Unit
* Unit::SelectNearbyTarget() const
10482 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10484 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10485 cell
.SetNoCreate();
10487 std::list
<Unit
*> targets
;
10490 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10491 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10493 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10494 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10496 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10497 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *GetMap());
10498 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *GetMap());
10501 // remove current target
10503 targets
.remove(getVictim());
10505 // remove not LoS targets
10506 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10508 if(!IsWithinLOSInMap(*tIter
))
10510 std::list
<Unit
*>::iterator tIter2
= tIter
;
10512 targets
.erase(tIter2
);
10518 // no appropriate targets
10519 if(targets
.empty())
10523 uint32 rIdx
= urand(0,targets
.size()-1);
10524 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10525 for(uint32 i
= 0; i
< rIdx
; ++i
)
10531 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10535 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10536 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10540 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10541 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10545 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10548 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10550 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10553 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10555 // Not apply this to creature casted spells with casttime==0
10556 if(CastingTime
==0 && GetTypeId()==TYPEID_UNIT
&& !((Creature
*)this)->isPet())
10559 if (CastingTime
> 7000) CastingTime
= 7000;
10560 if (CastingTime
< 1500) CastingTime
= 1500;
10562 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10563 CastingTime
= 3500;
10565 int32 overTime
= 0;
10567 bool DirectDamage
= false;
10568 bool AreaEffect
= false;
10570 for ( uint32 i
=0; i
<3;i
++)
10572 switch ( spellProto
->Effect
[i
] )
10574 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10575 case SPELL_EFFECT_POWER_DRAIN
:
10576 case SPELL_EFFECT_HEALTH_LEECH
:
10577 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10578 case SPELL_EFFECT_POWER_BURN
:
10579 case SPELL_EFFECT_HEAL
:
10580 DirectDamage
= true;
10582 case SPELL_EFFECT_APPLY_AURA
:
10583 switch ( spellProto
->EffectApplyAuraName
[i
] )
10585 case SPELL_AURA_PERIODIC_DAMAGE
:
10586 case SPELL_AURA_PERIODIC_HEAL
:
10587 case SPELL_AURA_PERIODIC_LEECH
:
10588 if ( GetSpellDuration(spellProto
) )
10589 overTime
= GetSpellDuration(spellProto
);
10592 // -5% per additional effect
10600 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10604 // Combined Spells with Both Over Time and Direct Damage
10605 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10607 // mainly for DoTs which are 3500 here otherwise
10608 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10609 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10610 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10611 // Portion to Over Time
10612 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10614 if ( damagetype
== DOT
)
10615 CastingTime
= uint32(CastingTime
* PtOT
);
10616 else if ( PtOT
< 1.0f
)
10617 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10622 // Area Effect Spells receive only half of bonus
10626 // -5% of total per any additional effect
10627 for ( uint8 i
=0; i
<effects
; ++i
)
10629 if ( CastingTime
> 175 )
10631 CastingTime
-= 175;
10640 return CastingTime
;
10643 void Unit::UpdateAuraForGroup(uint8 slot
)
10645 if(GetTypeId() == TYPEID_PLAYER
)
10647 Player
* player
= (Player
*)this;
10648 if(player
->GetGroup())
10650 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10651 player
->SetAuraUpdateMask(slot
);
10654 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10656 Pet
*pet
= ((Pet
*)this);
10657 if(pet
->isControlled())
10659 Unit
*owner
= GetOwner();
10660 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10662 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10663 pet
->SetAuraUpdateMask(slot
);
10669 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10671 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10672 return float(GetAttackTime(attType
))/1000.0f
;
10674 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10676 return 2.4; // fist attack
10678 switch (Weapon
->GetProto()->InventoryType
)
10680 case INVTYPE_2HWEAPON
:
10682 case INVTYPE_RANGED
:
10683 case INVTYPE_RANGEDRIGHT
:
10684 case INVTYPE_THROWN
:
10686 case INVTYPE_WEAPON
:
10687 case INVTYPE_WEAPONMAINHAND
:
10688 case INVTYPE_WEAPONOFFHAND
:
10690 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10694 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10696 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10697 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10698 if ((*itr
)->GetId() == spell_id
)
10704 bool Unit::IsUnderLastManaUseEffect() const
10706 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10709 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10711 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10713 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10716 player
->SetContestedPvPTimer(30000);
10717 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10719 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10720 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10721 // call MoveInLineOfSight for nearby contested guards
10722 SetVisibility(GetVisibility());
10724 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10726 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10727 // call MoveInLineOfSight for nearby contested guards
10728 SetVisibility(GetVisibility());
10732 void Unit::AddPetAura(PetAura
const* petSpell
)
10734 m_petAuras
.insert(petSpell
);
10735 if(Pet
* pet
= GetPet())
10736 pet
->CastPetAura(petSpell
);
10739 void Unit::RemovePetAura(PetAura
const* petSpell
)
10741 m_petAuras
.erase(petSpell
);
10742 if(Pet
* pet
= GetPet())
10743 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10746 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10748 Pet
* pet
= new Pet(HUNTER_PET
);
10750 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10756 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, GetGUID());
10757 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, GetGUID());
10758 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,getFaction());
10759 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10761 if(!pet
->InitStatsForLevel(creatureTarget
->getLevel()))
10763 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10768 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10769 // this enables pet details window (Shift+P)
10770 pet
->AIM_Initialize();
10771 pet
->InitPetCreateSpells();
10772 pet
->SetHealth(pet
->GetMaxHealth());
10777 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10779 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10781 if(!spellProcEvent
)
10783 // used to prevent spam in log about same non-handled spells
10784 static std::set
<uint32
> nonHandledSpellProcSet
;
10786 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10788 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10789 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10792 // spell.dbc use totally different flags, that only can create problems if used.
10796 // Check spellProcEvent data requirements
10797 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10800 // Check if current equipment allows aura to proc
10801 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10803 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10805 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10807 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10810 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10812 // Check if player is wearing shield
10813 Item
*item
= ((Player
*)this)->GetShield(true);
10814 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10819 float chance
= (float)spellProto
->procChance
;
10821 if(Player
* modOwner
= GetSpellModOwner())
10822 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10824 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10826 uint32 WeaponSpeed
= GetAttackTime(attType
);
10827 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10830 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10831 return roll_chance_f(chance
);
10834 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10836 // aura can be deleted at casts
10837 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10838 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10839 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10840 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10843 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10845 // current aura expire
10846 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10848 // next target selection
10849 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10852 if (spellProto
->EffectRadiusIndex
[effIdx
])
10853 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10855 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10857 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10859 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10861 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10863 // aura will applied from caster, but spell casted from current aura holder
10864 SpellModifier
*mod
= new SpellModifier
;
10865 mod
->op
= SPELLMOD_CHARGES
;
10866 mod
->value
= jumps
-5; // negative
10867 mod
->type
= SPELLMOD_FLAT
;
10868 mod
->spellId
= spellProto
->Id
;
10869 mod
->effectId
= effIdx
;
10870 mod
->lastAffected
= NULL
;
10871 mod
->mask
= spellProto
->SpellFamilyFlags
;
10874 caster
->AddSpellMod(mod
, true);
10875 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10876 caster
->AddSpellMod(mod
, false);
10882 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10886 void Unit::RemoveAurasAtChanneledTarget(SpellEntry
const* spellInfo
)
10888 uint64 target_guid
= GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
);
10890 if(!IS_UNIT_GUID(target_guid
))
10893 Unit
* target
= ObjectAccessor::GetUnit(*this, target_guid
);
10897 for (AuraMap::iterator iter
= target
->GetAuras().begin(); iter
!= target
->GetAuras().end(); )
10899 if (iter
->second
->GetId() == spellInfo
->Id
&& iter
->second
->GetCasterGUID()==GetGUID())
10900 target
->RemoveAura(iter
);