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 if (IsSingleTargetSpell((*i
).second
->GetSpellProto()))
4103 if(Unit
* caster
= (*i
).second
->GetCaster())
4105 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4106 scAuras
.remove((*i
).second
);
4110 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4115 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4117 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
4120 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4121 Aura
* Aur
= i
->second
;
4123 Aur
->SetRemoveMode(mode
);
4124 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4125 // remove aura from list before to prevent deleting it before
4127 ++m_removedAuras
; // internal count used by unit update
4129 // Status unsummoned at aura remove
4130 Totem
* statue
= NULL
;
4131 if(IsChanneledSpell(Aur
->GetSpellProto()))
4132 if(Unit
* caster
= Aur
->GetCaster())
4133 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4134 statue
= ((Totem
*)caster
);
4136 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4137 Aur
->ApplyModifier(false,true);
4144 // only way correctly remove all auras from list
4145 if( m_Auras
.empty() )
4148 i
= m_Auras
.begin();
4151 void Unit::RemoveAllAuras()
4153 while (!m_Auras
.empty())
4155 AuraMap::iterator iter
= m_Auras
.begin();
4160 void Unit::RemoveAllAurasOnDeath()
4162 // used just after dieing to remove all visible auras
4163 // and disable the mods for the passive ones
4164 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4166 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4167 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4173 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4175 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4176 if (iter
!= m_Auras
.end())
4178 if (iter
->second
->GetAuraDuration() < delaytime
)
4179 iter
->second
->SetAuraDuration(0);
4181 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4182 iter
->second
->UpdateAuraDuration();
4183 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4187 void Unit::_RemoveAllAuraMods()
4189 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4191 (*i
).second
->ApplyModifier(false);
4195 void Unit::_ApplyAllAuraMods()
4197 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4199 (*i
).second
->ApplyModifier(true);
4203 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4205 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4206 if (iter
!= m_Auras
.end())
4207 return iter
->second
;
4211 void Unit::AddDynObject(DynamicObject
* dynObj
)
4213 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4216 void Unit::RemoveDynObject(uint32 spellid
)
4218 if(m_dynObjGUIDs
.empty())
4220 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4222 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4225 i
= m_dynObjGUIDs
.erase(i
);
4227 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4230 i
= m_dynObjGUIDs
.erase(i
);
4237 void Unit::RemoveAllDynObjects()
4239 while(!m_dynObjGUIDs
.empty())
4241 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4244 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4248 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4250 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4252 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4255 i
= m_dynObjGUIDs
.erase(i
);
4259 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4266 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4268 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4270 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4273 i
= m_dynObjGUIDs
.erase(i
);
4277 if (dynObj
->GetSpellId() == spellId
)
4284 void Unit::AddGameObject(GameObject
* gameObj
)
4286 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4287 m_gameObj
.push_back(gameObj
);
4288 gameObj
->SetOwnerGUID(GetGUID());
4291 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4293 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4295 // GO created by some spell
4296 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4298 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4299 // Need activate spell use for owner
4300 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4301 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4303 gameObj
->SetOwnerGUID(0);
4304 m_gameObj
.remove(gameObj
);
4307 gameObj
->SetRespawnTime(0);
4312 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4314 if(m_gameObj
.empty())
4316 std::list
<GameObject
*>::iterator i
, next
;
4317 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4320 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4322 (*i
)->SetOwnerGUID(0);
4325 (*i
)->SetRespawnTime(0);
4329 next
= m_gameObj
.erase(i
);
4336 void Unit::RemoveAllGameObjects()
4338 // remove references to unit
4339 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4341 (*i
)->SetOwnerGUID(0);
4342 (*i
)->SetRespawnTime(0);
4344 i
= m_gameObj
.erase(i
);
4348 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4350 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4351 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4352 data
.append(target
->GetPackGUID());
4353 data
.append(GetPackGUID());
4354 data
<< uint32(SpellID
);
4355 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4356 data
<< uint8(damageSchoolMask
); // spell school
4357 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4358 data
<< uint32(Resist
); // resist
4359 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
4360 data
<< uint8(0); // unk isFromAura
4361 data
<< uint32(Blocked
); // blocked
4362 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4363 data
<< uint8(0); // isDebug?
4364 SendMessageToSet( &data
, true );
4367 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4369 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4370 data
<< uint32(spellID
);
4371 data
<< uint64(GetGUID());
4372 data
<< uint8(0); // can be 0 or 1
4373 data
<< uint32(1); // target count
4374 // for(i = 0; i < target count; ++i)
4375 data
<< uint64(target
->GetGUID()); // target GUID
4376 data
<< uint8(missInfo
);
4378 SendMessageToSet(&data
, true);
4381 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4383 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4385 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4386 data
<< (uint32
)HitInfo
;
4387 data
.append(GetPackGUID());
4388 data
.append(target
->GetPackGUID());
4389 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4391 data
<< (uint8
)SwingType
; // count?
4393 // for(i = 0; i < SwingType; ++i)
4394 data
<< (uint32
)damageSchoolMask
;
4395 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4396 // still need to double check damage
4397 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4398 data
<< (uint32
)AbsorbDamage
;
4399 data
<< (uint32
)Resist
;
4402 data
<< (uint32
)TargetState
;
4404 if( AbsorbDamage
== 0 ) //also 0x3E8 = 0x3E8, check when that happens
4410 data
<< (uint32
)BlockedAmount
;
4412 SendMessageToSet( &data
, true );
4415 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4417 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4419 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4421 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4422 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4423 // That is the question though if it's fully correct
4424 if(procSpell
&& !isTriggeredSpell
)
4426 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4428 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4429 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4430 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4431 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4432 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4434 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4436 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4437 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4438 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4439 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4440 attType
= RANGED_ATTACK
;
4443 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4444 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4446 // Not much to do if no flags are set.
4449 // 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
4450 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4451 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4454 // Now go on with a victim's events'n'auras
4455 // Not much to do if no flags are set or there is no victim
4456 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4458 // 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
4459 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4460 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4464 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4469 uint32 procAttacker
= PROC_FLAG_NONE
;
4470 uint32 procVictim
= PROC_FLAG_NONE
;
4474 case MELEE_HIT_EVADE
:
4476 case MELEE_HIT_MISS
:
4477 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4479 procAttacker
= PROC_FLAG_MISS
;
4482 case MELEE_HIT_BLOCK_CRIT
:
4483 case MELEE_HIT_CRIT
:
4484 if(spellCasted
&& attType
== BASE_ATTACK
)
4486 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4487 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4488 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4490 procVictim
|= PROC_FLAG_BLOCK
;
4491 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4494 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4496 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4497 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4501 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4502 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4505 case MELEE_HIT_PARRY
:
4506 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4507 procVictim
= PROC_FLAG_PARRY
;
4509 case MELEE_HIT_BLOCK
:
4510 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4511 procVictim
= PROC_FLAG_BLOCK
;
4513 case MELEE_HIT_DODGE
:
4514 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4515 procVictim
= PROC_FLAG_DODGE
;
4517 case MELEE_HIT_CRUSHING
:
4518 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4520 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4521 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4525 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4526 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4530 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4532 procAttacker
= PROC_FLAG_HIT_MELEE
;
4533 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4537 procAttacker
= PROC_FLAG_HIT_RANGED
;
4538 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4544 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4546 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4547 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4550 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, SpellEntry
const *hasteSpell
, uint32
/*effIndex*/, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4552 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4553 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4555 uint32 triggered_spell_id
= 0;
4556 Unit
* target
= pVictim
;
4557 int32 basepoints0
= 0;
4559 switch(hasteSpell
->SpellFamilyName
)
4561 case SPELLFAMILY_ROGUE
:
4563 switch(hasteSpell
->Id
)
4569 target
= SelectNearbyTarget();
4572 basepoints0
= damage
;
4573 triggered_spell_id
= 22482;
4581 // processed charge only counting case
4582 if(!triggered_spell_id
)
4585 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4589 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4594 if(!target
|| target
!=this && !target
->isAlive())
4597 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4601 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4603 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4605 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4606 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4611 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, SpellEntry
const *dummySpell
, uint32 effIndex
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4613 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4614 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4616 uint32 triggered_spell_id
= 0;
4617 Unit
* target
= pVictim
;
4618 int32 basepoints0
= 0;
4620 switch(dummySpell
->SpellFamilyName
)
4622 case SPELLFAMILY_GENERIC
:
4624 switch (dummySpell
->Id
)
4630 // prevent damage back from weapon special attacks
4631 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4634 // return damage % to attacker but < 50% own total health
4635 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4636 if(basepoints0
> GetMaxHealth()/2)
4637 basepoints0
= GetMaxHealth()/2;
4639 triggered_spell_id
= 25997;
4647 // prevent chain of triggered spell from same triggered spell
4648 if(procSpell
&& procSpell
->Id
==26654)
4651 target
= SelectNearbyTarget();
4655 triggered_spell_id
= 26654;
4661 if (!procSpell
|| procSpell
->Id
== 24659)
4663 // Need remove one 24659 aura
4664 RemoveSingleAuraFromStack(24659, 0);
4665 RemoveSingleAuraFromStack(24659, 1);
4668 // Restless Strength
4671 // Need remove one 24662 aura
4672 RemoveSingleAuraFromStack(24662, 0);
4675 // Adaptive Warding (Frostfire Regalia set)
4683 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4684 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4686 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4688 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4698 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4700 case SPELL_SCHOOL_NORMAL
:
4701 case SPELL_SCHOOL_HOLY
:
4702 return false; // ignored
4703 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4704 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4705 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4706 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4707 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4715 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4723 for(int j
= 0; j
< 3; ++j
)
4725 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4734 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4736 case SPELL_SCHOOL_NORMAL
:
4737 return false; // ignore
4738 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4739 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4740 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4741 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4742 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4743 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4751 // Mana Leech (Passive) (Priest Pet Aura)
4755 target
= GetOwner();
4759 basepoints0
= int32(damage
* 2.5f
); // manaregen
4760 triggered_spell_id
= 34650;
4766 // Cast finish spell at last charge
4767 if (triggeredByAura
->m_procCharges
> 1)
4771 triggered_spell_id
= 33494;
4774 // Twisted Reflection (boss spell)
4776 triggered_spell_id
= 21064;
4778 // Vampiric Aura (boss spell)
4781 basepoints0
= 3 * damage
; // 300%
4782 if (basepoints0
< 0)
4785 triggered_spell_id
= 31285;
4789 // Aura of Madness (Darkmoon Card: Madness trinket)
4790 //=====================================================
4791 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4792 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4793 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4794 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4795 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4796 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4797 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4798 // 41011 Martyr Complex: +35 stamina (All classes)
4799 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4800 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4803 if(GetTypeId() != TYPEID_PLAYER
)
4806 // Select class defined buff
4809 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4810 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4812 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4813 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4816 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4817 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4819 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4820 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4823 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4824 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4825 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4826 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4828 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4829 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4832 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4834 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4835 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4843 if (roll_chance_i(10))
4844 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4848 // TODO: need find item for aura and triggered spells
4849 // Sunwell Exalted Caster Neck (??? neck)
4850 // cast ??? Light's Wrath if Exalted by Aldor
4851 // cast ??? Arcane Bolt if Exalted by Scryers*/
4853 return false; // disable for while
4856 if(GetTypeId() != TYPEID_PLAYER)
4859 // Get Aldor reputation rank
4860 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4863 triggered_spell_id = ???
4866 // Get Scryers reputation rank
4867 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4869 triggered_spell_id = ???
4874 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4875 // cast 45479 Light's Wrath if Exalted by Aldor
4876 // cast 45429 Arcane Bolt if Exalted by Scryers
4879 if(GetTypeId() != TYPEID_PLAYER
)
4882 // Get Aldor reputation rank
4883 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4886 triggered_spell_id
= 45479;
4889 // Get Scryers reputation rank
4890 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4892 triggered_spell_id
= 45429;
4897 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4898 // cast 45480 Light's Strength if Exalted by Aldor
4899 // cast 45428 Arcane Strike if Exalted by Scryers
4902 if(GetTypeId() != TYPEID_PLAYER
)
4905 // Get Aldor reputation rank
4906 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4909 triggered_spell_id
= 45480;
4912 // Get Scryers reputation rank
4913 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4915 triggered_spell_id
= 45428;
4920 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4921 // cast 45431 Arcane Insight if Exalted by Aldor
4922 // cast 45432 Light's Ward if Exalted by Scryers
4925 if(GetTypeId() != TYPEID_PLAYER
)
4928 // Get Aldor reputation rank
4929 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4932 triggered_spell_id
= 45432;
4935 // Get Scryers reputation rank
4936 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4939 triggered_spell_id
= 45431;
4944 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4945 // cast 45478 Light's Salvation if Exalted by Aldor
4946 // cast 45430 Arcane Surge if Exalted by Scryers
4949 if(GetTypeId() != TYPEID_PLAYER
)
4952 // Get Aldor reputation rank
4953 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4956 triggered_spell_id
= 45478;
4959 // Get Scryers reputation rank
4960 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4962 triggered_spell_id
= 45430;
4970 case SPELLFAMILY_MAGE
:
4973 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
4975 if (getPowerType() != POWER_MANA
)
4979 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
4981 triggered_spell_id
= 29442;
4984 // Master of Elements
4985 if (dummySpell
->SpellIconID
== 1920)
4991 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
4992 if( basepoints0
<=0 )
4996 triggered_spell_id
= 29077;
4999 switch(dummySpell
->Id
)
5008 switch (dummySpell
->Id
)
5010 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5011 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5012 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5013 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5014 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5016 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5020 triggered_spell_id
= 12654;
5026 //last charge and crit
5027 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5029 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5030 return true; // charge counting (will removed)
5033 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5034 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5039 case SPELLFAMILY_WARRIOR
:
5042 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5044 // check attack comes not from behind
5045 if (!HasInArc(M_PI
, pVictim
))
5048 triggered_spell_id
= 22858;
5053 case SPELLFAMILY_WARLOCK
:
5055 // Seed of Corruption
5056 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5058 Modifier
* mod
= triggeredByAura
->GetModifier();
5059 // if damage is more than need or target die from damage deal finish spell
5060 // FIX ME: not triggered currently at death
5061 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5063 // remember guid before aura delete
5064 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5066 // Remove aura (before cast for prevent infinite loop handlers)
5067 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5069 // Cast finish spell (triggeredByAura already not exist!)
5070 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5071 return true; // no hidden cooldown
5075 mod
->m_amount
-=damage
;
5078 // Seed of Corruption (Mobs cast) - no die req
5079 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5081 Modifier
* mod
= triggeredByAura
->GetModifier();
5082 // if damage is more than need deal finish spell
5083 if( mod
->m_amount
<= 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, 32865, true, castItem
, NULL
, casterGuid
);
5093 return true; // no hidden cooldown
5096 mod
->m_amount
-=damage
;
5099 switch(dummySpell
->Id
)
5106 triggered_spell_id
= 17941;
5115 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5117 triggered_spell_id
= 30294;
5120 // Shadowflame (Voidheart Raiment set bonus)
5123 triggered_spell_id
= 37379;
5126 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5134 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5135 triggered_spell_id
= 37382;
5138 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5141 triggered_spell_id
= 37378;
5147 case SPELLFAMILY_PRIEST
:
5150 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5152 if(!pVictim
|| !pVictim
->isAlive())
5155 // pVictim is caster of aura
5156 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5160 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5161 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5162 return true; // no hidden cooldown
5164 switch(dummySpell
->Id
)
5169 if(!pVictim
|| !pVictim
->isAlive())
5172 // pVictim is caster of aura
5173 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5177 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5178 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5179 return true; // no hidden cooldown
5181 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5184 // Shadow Word: Pain
5185 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5186 triggered_spell_id
= 40441;
5188 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5189 triggered_spell_id
= 40440;
5196 // Oracle Healing Bonus ("Garments of the Oracle" set)
5200 basepoints0
= int32(damage
* 10/100);
5202 triggered_spell_id
= 26170;
5205 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5208 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5212 basepoints0
= int32(damage
* 2 / 100);
5214 triggered_spell_id
= 39373;
5217 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5220 triggered_spell_id
= 28810;
5226 case SPELLFAMILY_DRUID
:
5228 switch(dummySpell
->Id
)
5230 // Healing Touch (Dreamwalker Raiment set)
5234 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5236 triggered_spell_id
= 28742;
5239 // Healing Touch Refund (Idol of Longevity trinket)
5243 triggered_spell_id
= 28848;
5246 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5251 triggered_spell_id
= 37238;
5254 // Druid Tier 6 Trinket
5260 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5262 triggered_spell_id
= 40445;
5266 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5268 triggered_spell_id
= 40446;
5271 // Mangle (cat/bear)
5272 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5274 triggered_spell_id
= 40452;
5280 if (!roll_chance_f(chance
))
5289 // Deadly Interrupt Effect
5290 triggered_spell_id
= 32747;
5296 case SPELLFAMILY_ROGUE
:
5298 switch(dummySpell
->Id
)
5300 // Deadly Throw Interrupt
5303 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5307 triggered_spell_id
= 32747;
5312 if( dummySpell
->SpellIconID
== 2116 )
5317 // only rogue's finishing moves (maybe need additional checks)
5318 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5319 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5323 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5324 if(basepoints0
<= 0)
5328 triggered_spell_id
= 31663;
5333 case SPELLFAMILY_HUNTER
:
5335 // Thrill of the Hunt
5336 if ( dummySpell
->SpellIconID
== 2236 )
5342 basepoints0
= procSpell
->manaCost
* 40/100;
5343 if(basepoints0
<= 0)
5347 triggered_spell_id
= 34720;
5352 case SPELLFAMILY_PALADIN
:
5354 // Seal of Righteousness - melee proc dummy
5355 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5357 if(GetTypeId() != TYPEID_PLAYER
)
5361 switch (triggeredByAura
->GetId())
5363 case 21084: spellId
= 25742; break; // Rank 1
5364 case 20287: spellId
= 25740; break; // Rank 2
5365 case 20288: spellId
= 25739; break; // Rank 3
5366 case 20289: spellId
= 25738; break; // Rank 4
5367 case 20290: spellId
= 25737; break; // Rank 5
5368 case 20291: spellId
= 25736; break; // Rank 6
5369 case 20292: spellId
= 25735; break; // Rank 7
5370 case 20293: spellId
= 25713; break; // Rank 8
5371 case 27155: spellId
= 27156; break; // Rank 9
5373 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5376 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5377 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5379 float damageBasePoints
;
5380 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5382 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5384 // one hand weapon/no weapon
5385 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5387 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5389 // apply damage bonuses manually
5390 if(damagePoint
>= 0)
5391 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5393 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5394 return true; // no hidden cooldown
5396 // Seal of Blood do damage trigger
5397 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5399 switch(triggeredByAura
->GetEffIndex())
5402 // prevent chain triggering
5403 if(procSpell
&& procSpell
->Id
==31893 )
5406 triggered_spell_id
= 31893;
5411 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5413 triggered_spell_id
= 32221;
5419 switch(dummySpell
->Id
)
5421 // Holy Power (Redemption Armor set)
5427 // Set class defined buff
5428 switch (pVictim
->getClass())
5434 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5438 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5442 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5445 triggered_spell_id
= 28790; // Increases the friendly target's armor
5455 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5458 triggered_spell_id
= 31803;
5465 // if healed by another unit (pVictim)
5470 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5472 triggered_spell_id
= 31786;
5475 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5483 // Flash of light/Holy light
5484 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5486 triggered_spell_id
= 40471;
5490 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5492 triggered_spell_id
= 40472;
5498 if (!roll_chance_f(chance
))
5506 case SPELLFAMILY_SHAMAN
:
5508 switch(dummySpell
->Id
)
5510 // Totemic Power (The Earthshatterer set)
5516 // Set class defined buff
5517 switch (pVictim
->getClass())
5523 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5527 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5531 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5534 triggered_spell_id
= 28827; // Increases the friendly target's armor
5541 // Lesser Healing Wave (Totem of Flowing Water Relic)
5545 triggered_spell_id
= 28850;
5548 // Windfury Weapon (Passive) 1-5 Ranks
5551 if(GetTypeId()!=TYPEID_PLAYER
)
5554 if(!castItem
|| !castItem
->IsEquipped())
5557 // custom cooldown processing case
5558 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5562 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5564 case 283: spellId
= 33757; break; //1 Rank
5565 case 284: spellId
= 33756; break; //2 Rank
5566 case 525: spellId
= 33755; break; //3 Rank
5567 case 1669:spellId
= 33754; break; //4 Rank
5568 case 2636:spellId
= 33727; break; //5 Rank
5571 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5572 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5577 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5578 if(!windfurySpellEntry
)
5580 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5584 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5587 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5589 // Value gained from additional AP
5590 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5591 triggered_spell_id
= 33750;
5596 // Value gained from additional AP
5597 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5598 triggered_spell_id
= 25504;
5601 // apply cooldown before cast to prevent processing itself
5603 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5606 for ( uint32 i
= 0; i
<2; ++i
)
5607 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5611 // Shaman Tier 6 Trinket
5618 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5620 triggered_spell_id
= 40465; // Lightning Bolt
5623 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5625 triggered_spell_id
= 40465; // Lesser Healing Wave
5628 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5630 triggered_spell_id
= 40466; // Stormstrike
5636 if (!roll_chance_f(chance
))
5645 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5647 if(GetTypeId() != TYPEID_PLAYER
)
5651 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5653 triggered_spell_id
= 379;
5656 // Lightning Overload
5657 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5659 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5662 // custom cooldown processing case
5663 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5667 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5668 switch (procSpell
->Id
)
5671 case 403: spellId
= 45284; break; // Rank 1
5672 case 529: spellId
= 45286; break; // Rank 2
5673 case 548: spellId
= 45287; break; // Rank 3
5674 case 915: spellId
= 45288; break; // Rank 4
5675 case 943: spellId
= 45289; break; // Rank 5
5676 case 6041: spellId
= 45290; break; // Rank 6
5677 case 10391: spellId
= 45291; break; // Rank 7
5678 case 10392: spellId
= 45292; break; // Rank 8
5679 case 15207: spellId
= 45293; break; // Rank 9
5680 case 15208: spellId
= 45294; break; // Rank 10
5681 case 25448: spellId
= 45295; break; // Rank 11
5682 case 25449: spellId
= 45296; break; // Rank 12
5684 case 421: spellId
= 45297; break; // Rank 1
5685 case 930: spellId
= 45298; break; // Rank 2
5686 case 2860: spellId
= 45299; break; // Rank 3
5687 case 10605: spellId
= 45300; break; // Rank 4
5688 case 25439: spellId
= 45301; break; // Rank 5
5689 case 25442: spellId
= 45302; break; // Rank 6
5691 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5694 // No thread generated mod
5695 SpellModifier
*mod
= new SpellModifier
;
5696 mod
->op
= SPELLMOD_THREAT
;
5698 mod
->type
= SPELLMOD_PCT
;
5699 mod
->spellId
= dummySpell
->Id
;
5701 mod
->lastAffected
= NULL
;
5702 mod
->mask
= 0x0000000000000003LL
;
5704 ((Player
*)this)->AddSpellMod(mod
, true);
5706 // Remove cooldown (Chain Lightning - have Category Recovery time)
5707 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5708 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5710 // Hmmm.. in most case spells already set half basepoints but...
5711 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5713 // 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.
5714 // So - no add changes :)
5715 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5717 ((Player
*)this)->AddSpellMod(mod
, false);
5719 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5720 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5730 // processed charge only counting case
5731 if(!triggered_spell_id
)
5734 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5738 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5743 if(!target
|| target
!=this && !target
->isAlive())
5746 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5750 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5752 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5754 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5755 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5760 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5762 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5764 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5765 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5767 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5768 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5769 int32 basepoints0
= 0;
5771 switch(auraSpellInfo
->SpellFamilyName
)
5773 case SPELLFAMILY_GENERIC
:
5775 switch(auraSpellInfo
->Id
)
5777 // Aegis of Preservation
5779 //Aegis Heal (instead non-existed triggered spell)
5780 triggered_spell_id
= 23781;
5783 // Elune's Touch (moonkin mana restore)
5786 // Elune's Touch (instead non-existed triggered spell)
5787 triggered_spell_id
= 33926;
5788 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5795 // only for cast with mana price
5796 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5798 break; // fall through to normal cast
5803 // at melee hit call std triggered spell
5804 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5805 break; // fall through to normal cast
5807 // Mark of Conquest - else (at range hit) called custom case
5808 triggered_spell_id
= 39557;
5814 return true; // nothing to do
5815 // Forgotten Knowledge (Blade of Wizardry)
5817 // only for harmful enemy targeted spell
5818 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5820 break; // fall through to normal cast
5821 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5824 // proc only at non-crit hits
5825 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5827 break; // fall through to normal cast
5829 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5835 //only periodic damage can trigger spell
5837 for(int j
= 0; j
< 3; ++j
)
5839 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5840 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5841 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5850 break; // fall through to normal cast
5852 // Evasive Maneuvers (Commendation of Kael'thas)
5855 // damage taken that reduces below 35% health
5856 // does NOT mean you must have been >= 35% before
5857 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5859 break; // fall through to normal cast
5863 switch(triggered_spell_id
)
5868 // applied only for main target
5869 if(!pVictim
|| pVictim
!= getVictim())
5872 // continue normal case
5875 // Shamanistic Rage triggered spell
5877 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5882 case SPELLFAMILY_MAGE
:
5884 switch(auraSpellInfo
->SpellIconID
)
5888 //Blazing Speed (instead non-existed triggered spell)
5889 triggered_spell_id
= 31643;
5893 switch(auraSpellInfo
->Id
)
5895 // Persistent Shield (Scarab Brooch)
5897 basepoints0
= int32(damage
* 0.15f
);
5902 case SPELLFAMILY_WARRIOR
:
5905 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5907 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5908 //and effect[1]==TriggerSpell
5909 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5911 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5914 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5915 break; // fall through to normal cast
5919 case SPELLFAMILY_WARLOCK
:
5922 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5924 // last case for Hellfire that damage caster also but don't must stun caster
5925 if( pVictim
== this )
5930 switch (triggeredByAura
->GetId())
5932 case 18096: chance
= 13.0f
; break;
5933 case 18073: chance
= 26.0f
; break;
5935 if (!roll_chance_f(chance
))
5938 // Pyroclasm (instead non-existed triggered spell)
5939 triggered_spell_id
= 18093;
5944 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5947 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5948 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5950 //Improved Drain Soul
5951 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5953 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5954 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5957 triggered_spell_id
= 18371;
5965 break; // fall through to normal cast
5969 case SPELLFAMILY_PRIEST
:
5972 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
5974 switch (triggeredByAura
->GetSpellProto()->Id
)
5976 case 27811: triggered_spell_id
= 27813; break;
5977 case 27815: triggered_spell_id
= 27817; break;
5978 case 27816: triggered_spell_id
= 27818; break;
5980 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
5984 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
5985 basepoints0
= heal_amount
/3;
5990 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
==7958)
5992 switch(triggeredByAura
->GetSpellProto()->Id
)
5995 triggered_spell_id
= 28377; break; // Rank 1
5997 triggered_spell_id
= 28378; break; // Rank 2
5999 triggered_spell_id
= 28379; break; // Rank 3
6001 triggered_spell_id
= 28380; break; // Rank 4
6003 triggered_spell_id
= 28381; break; // Rank 5
6005 triggered_spell_id
= 28382; break; // Rank 6
6007 triggered_spell_id
= 28385; break; // Rank 7
6009 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6017 case SPELLFAMILY_DRUID
:
6019 switch(auraSpellInfo
->Id
)
6021 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6024 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6026 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6027 triggered_spell_id
= 34299;
6030 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6037 triggered_spell_id
=37340; break;// Ursine Blessing
6039 triggered_spell_id
=37341; break;// Feline Blessing
6041 triggered_spell_id
=37342; break;// Slyvan Blessing
6043 triggered_spell_id
=37343; break;// Lunar Blessing
6045 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6056 case SPELLFAMILY_ROGUE
:
6058 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6060 switch(auraSpellInfo
->SpellIconID
)
6065 // skip non offhand attacks
6066 if(attackType
!=OFF_ATTACK
)
6068 break; // fall through to normal cast
6074 case SPELLFAMILY_PALADIN
:
6076 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6078 switch(auraSpellInfo
->Id
)
6080 // Lightning Capacitor
6083 // trinket ProcTriggerSpell but for safe checks for player
6084 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6087 if(((Player
*)this)->HasSpellCooldown(37657))
6091 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6092 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6093 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6097 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6098 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6099 if((*itr
)->GetId()==37658)
6102 // release at 3 aura in stack
6104 return true; // main triggered spell casted anyway
6106 RemoveAurasDueToSpell(37658);
6107 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6112 // Healing Trance (instead non-existed triggered spell)
6113 triggered_spell_id
= 37706;
6116 // HoTs on Heals (Fel Reaver's Piston trinket)
6119 // at direct heal effect
6120 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6123 // single proc at time
6124 AuraList
const& scAuras
= GetSingleCastAuras();
6125 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6126 if((*itr
)->GetId()==triggered_spell_id
)
6129 // positive cast at victim instead self
6134 switch(auraSpellInfo
->SpellIconID
)
6138 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6146 // procspell is triggered spell but we need mana cost of original casted spell
6147 uint32 originalSpellId
= procSpell
->Id
;
6150 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6152 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6154 switch(procSpell
->Id
)
6156 case 25914: originalSpellId
= 20473; break;
6157 case 25913: originalSpellId
= 20929; break;
6158 case 25903: originalSpellId
= 20930; break;
6159 case 27175: originalSpellId
= 27174; break;
6160 case 33074: originalSpellId
= 33072; break;
6162 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6168 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6171 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6175 // percent stored in effect 1 (class scripts) base points
6176 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6178 basepoints0
= originalSpell
->manaCost
*percent
/100;
6179 triggered_spell_id
= 20272;
6188 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6190 switch(auraSpellInfo
->SpellIconID
)
6192 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6195 if(!pVictim
|| !pVictim
->isAlive())
6198 switch(triggeredByAura
->GetSpellProto()->Id
)
6201 triggered_spell_id
= 20268; // Rank 1
6204 triggered_spell_id
= 20352; // Rank 2
6207 triggered_spell_id
= 20353; // Rank 3
6210 triggered_spell_id
= 27165; // Rank 4
6213 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6217 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6218 return true; // no hidden cooldown
6220 //Judgement of Light
6223 if(!pVictim
|| !pVictim
->isAlive())
6226 // overwrite non existing triggered spell call in spell.dbc
6227 switch(triggeredByAura
->GetSpellProto()->Id
)
6230 triggered_spell_id
= 20267; // Rank 1
6233 triggered_spell_id
= 20341; // Rank 2
6236 triggered_spell_id
= 20342; // Rank 3
6239 triggered_spell_id
= 20343; // Rank 4
6242 triggered_spell_id
= 27163; // Rank 5
6245 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6248 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6249 return true; // no hidden cooldown
6253 // custom check for proc spell
6254 switch(auraSpellInfo
->Id
)
6256 // Bonus Healing (item spell)
6259 if(!pVictim
|| !pVictim
->isAlive())
6262 // bonus if health < 50%
6263 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6266 // cast at target positive spell
6271 switch(triggered_spell_id
)
6275 // prevent chain of triggered spell from same triggered spell
6276 if(procSpell
&& procSpell
->Id
==20424)
6282 case SPELLFAMILY_SHAMAN
:
6284 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6286 switch(auraSpellInfo
->SpellIconID
)
6290 switch(auraSpellInfo
->Id
)
6292 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6294 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6295 triggered_spell_id
= 23552;
6299 case 23552: // Lightning Shield - trigger shield damage
6301 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6302 triggered_spell_id
= 27635;
6309 // Mana Surge (Shaman T1 bonus)
6315 basepoints0
= procSpell
->manaCost
* 35/100;
6316 triggered_spell_id
= 23571;
6323 if(GetTypeId()!=TYPEID_PLAYER
)
6326 // damage taken that reduces below 30% health
6327 // does NOT mean you must have been >= 30% before
6328 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6331 triggered_spell_id
= 31616;
6333 // need check cooldown now
6334 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6337 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6339 if(pVictim
&& pVictim
->isAlive())
6340 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6346 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6347 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
==7358)
6354 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
==37)
6356 // overwrite non existing triggered spell call in spell.dbc
6357 switch(triggeredByAura
->GetSpellProto()->Id
)
6360 triggered_spell_id
= 26364; break; // Rank 1
6362 triggered_spell_id
= 26365; break; // Rank 2
6364 triggered_spell_id
= 26366; break; // Rank 3
6366 triggered_spell_id
= 26367; break; // Rank 4
6368 triggered_spell_id
= 26369; break; // Rank 5
6370 triggered_spell_id
= 26370; break; // Rank 6
6372 triggered_spell_id
= 26363; break; // Rank 7
6374 triggered_spell_id
= 26371; break; // Rank 8
6376 triggered_spell_id
= 26372; break; // Rank 9
6378 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6389 // standard non-dummy case
6390 if(!triggered_spell_id
)
6392 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6396 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6400 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6404 // not allow proc extra attack spell at extra attack
6405 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6408 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6412 if(!target
|| target
!=this && !target
->isAlive())
6416 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6418 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6420 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6421 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6426 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, int32 scriptId
, uint32
/*damage*/, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6428 if(!pVictim
|| !pVictim
->isAlive())
6431 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6432 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6434 uint32 triggered_spell_id
= 0;
6438 case 836: // Improved Blizzard (Rank 1)
6440 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6442 triggered_spell_id
= 12484;
6445 case 988: // Improved Blizzard (Rank 2)
6447 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6449 triggered_spell_id
= 12485;
6452 case 989: // Improved Blizzard (Rank 3)
6454 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6456 triggered_spell_id
= 12486;
6459 case 4086: // Improved Mend Pet (Rank 1)
6460 case 4087: // Improved Mend Pet (Rank 2)
6462 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6463 if(!roll_chance_i(chance
))
6466 triggered_spell_id
= 24406;
6469 case 4533: // Dreamwalker Raiment 2 pieces bonus
6472 if (!roll_chance_i(50))
6475 switch (pVictim
->getPowerType())
6477 case POWER_MANA
: triggered_spell_id
= 28722; break;
6478 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6479 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6485 case 4537: // Dreamwalker Raiment 6 pieces bonus
6486 triggered_spell_id
= 28750; // Blessing of the Claw
6488 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6489 triggered_spell_id
= 37445; // Mana Surge
6494 if(!triggered_spell_id
)
6497 // standard non-dummy case
6498 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6502 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6506 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6509 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6511 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6512 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6517 void Unit::setPowerType(Powers new_powertype
)
6519 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6521 if(GetTypeId() == TYPEID_PLAYER
)
6523 if(((Player
*)this)->GetGroup())
6524 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6526 else if(((Creature
*)this)->isPet())
6528 Pet
*pet
= ((Pet
*)this);
6529 if(pet
->isControlled())
6531 Unit
*owner
= GetOwner();
6532 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6533 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6537 switch(new_powertype
)
6543 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6544 SetPower( POWER_RAGE
,0);
6547 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6548 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6551 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6552 SetPower( POWER_ENERGY
,0);
6554 case POWER_HAPPINESS
:
6555 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6556 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6561 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6563 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6566 static uint64 guid
= 0; // prevent repeating spam same faction problem
6568 if(GetGUID() != guid
)
6570 if(GetTypeId() == TYPEID_PLAYER
)
6571 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6573 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6580 bool Unit::IsHostileTo(Unit
const* unit
) const
6582 // always non-hostile to self
6586 // always non-hostile to GM in GM mode
6587 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6590 // always hostile to enemy
6591 if(getVictim()==unit
|| unit
->getVictim()==this)
6594 // test pet/charm masters instead pers/charmeds
6595 Unit
const* testerOwner
= GetCharmerOrOwner();
6596 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6598 // always hostile to owner's enemy
6599 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6602 // always hostile to enemy owner
6603 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6606 // always hostile to owner of owner's enemy
6607 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6610 Unit
const* tester
= testerOwner
? testerOwner
: this;
6611 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6613 // always non-hostile to target with common owner, or to owner/pet
6617 // special cases (Duel, etc)
6618 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6620 Player
const* pTester
= (Player
const*)tester
;
6621 Player
const* pTarget
= (Player
const*)target
;
6624 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6628 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6632 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6636 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6640 // Green/Blue (can't attack)
6641 if(pTester
->GetTeam()==pTarget
->GetTeam())
6644 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6645 return pTester
->IsPvP() && pTarget
->IsPvP();
6648 // faction base cases
6649 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6650 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6651 if(!tester_faction
|| !target_faction
)
6654 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6657 // PvC forced reaction and reputation case
6658 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6661 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6662 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6663 return forceItr
->second
<= REP_HOSTILE
;
6665 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6666 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6667 if(raw_target_faction
->reputationListID
>=0)
6668 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6669 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6671 // CvP forced reaction and reputation case
6672 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6675 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6676 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6677 return forceItr
->second
<= REP_HOSTILE
;
6679 // apply reputation state
6680 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6681 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6682 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6685 // common faction based case (CvC,PvC,CvP)
6686 return tester_faction
->IsHostileTo(*target_faction
);
6689 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6691 // always friendly to self
6695 // always friendly to GM in GM mode
6696 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6699 // always non-friendly to enemy
6700 if(getVictim()==unit
|| unit
->getVictim()==this)
6703 // test pet/charm masters instead pers/charmeds
6704 Unit
const* testerOwner
= GetCharmerOrOwner();
6705 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6707 // always non-friendly to owner's enemy
6708 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6711 // always non-friendly to enemy owner
6712 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6715 // always non-friendly to owner of owner's enemy
6716 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6719 Unit
const* tester
= testerOwner
? testerOwner
: this;
6720 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6722 // always friendly to target with common owner, or to owner/pet
6726 // special cases (Duel)
6727 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6729 Player
const* pTester
= (Player
const*)tester
;
6730 Player
const* pTarget
= (Player
const*)target
;
6733 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6737 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6741 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6745 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6749 // Green/Blue (non-attackable)
6750 if(pTester
->GetTeam()==pTarget
->GetTeam())
6753 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6754 return !pTarget
->IsPvP();
6757 // faction base cases
6758 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6759 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6760 if(!tester_faction
|| !target_faction
)
6763 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6766 // PvC forced reaction and reputation case
6767 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6770 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6771 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6772 return forceItr
->second
>= REP_FRIENDLY
;
6774 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6775 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6776 if(raw_target_faction
->reputationListID
>=0)
6777 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6778 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6780 // CvP forced reaction and reputation case
6781 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6784 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6785 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6786 return forceItr
->second
>= REP_FRIENDLY
;
6788 // apply reputation state
6789 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6790 if(raw_tester_faction
->reputationListID
>=0 )
6791 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6794 // common faction based case (CvC,PvC,CvP)
6795 return tester_faction
->IsFriendlyTo(*target_faction
);
6798 bool Unit::IsHostileToPlayers() const
6800 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6804 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6805 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6808 return my_faction
->IsHostileToPlayers();
6811 bool Unit::IsNeutralToAll() const
6813 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6817 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6818 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6821 return my_faction
->IsNeutralToAll();
6824 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6826 if(!victim
|| victim
== this)
6829 // dead units can neither attack nor be attacked
6830 if(!isAlive() || !victim
->isAlive())
6833 // player cannot attack in mount state
6834 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6837 // nobody can attack GM in GM-mode
6838 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6840 if(((Player
*)victim
)->isGameMaster())
6845 if(((Creature
*)victim
)->IsInEvadeMode())
6849 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6850 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6851 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6855 if (m_attacking
== victim
)
6857 // switch to melee attack from ranged/magic
6858 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6860 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6861 SendAttackStart(victim
);
6870 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6873 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6874 m_attacking
= victim
;
6875 m_attacking
->_addAttacker(this);
6877 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6878 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6880 if(GetTypeId()==TYPEID_UNIT
)
6882 WorldPacket
data(SMSG_AI_REACTION
, 12);
6884 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6885 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6887 ((Creature
*)this)->CallAssistence();
6888 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6891 // delay offhand weapon attack to next attack time
6892 if(haveOffhandWeapon())
6893 resetAttackTimer(OFF_ATTACK
);
6896 SendAttackStart(victim
);
6901 bool Unit::AttackStop()
6906 Unit
* victim
= m_attacking
;
6908 m_attacking
->_removeAttacker(this);
6912 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6914 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6916 InterruptSpell(CURRENT_MELEE_SPELL
);
6918 if( GetTypeId()==TYPEID_UNIT
)
6920 // reset call assistance
6921 ((Creature
*)this)->SetNoCallAssistence(false);
6924 SendAttackStop(victim
);
6929 void Unit::CombatStop(bool cast
)
6931 if(cast
& IsNonMeleeSpellCasted(false))
6932 InterruptNonMeleeSpells(false);
6935 RemoveAllAttackers();
6936 if( GetTypeId()==TYPEID_PLAYER
)
6937 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6941 void Unit::CombatStopWithPets(bool cast
)
6944 if(Pet
* pet
= GetPet())
6945 pet
->CombatStop(cast
);
6946 if(Unit
* charm
= GetCharm())
6947 charm
->CombatStop(cast
);
6948 if(GetTypeId()==TYPEID_PLAYER
)
6950 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6951 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6952 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6953 guardian
->CombatStop(cast
);
6957 bool Unit::isAttackingPlayer() const
6959 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
6962 Pet
* pet
= GetPet();
6963 if(pet
&& pet
->isAttackingPlayer())
6966 Unit
* charmed
= GetCharm();
6967 if(charmed
&& charmed
->isAttackingPlayer())
6970 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
6974 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
6975 if(totem
&& totem
->isAttackingPlayer())
6983 void Unit::RemoveAllAttackers()
6985 while (!m_attackers
.empty())
6987 AttackerSet::iterator iter
= m_attackers
.begin();
6988 if(!(*iter
)->AttackStop())
6990 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
6991 m_attackers
.erase(iter
);
6996 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7000 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7002 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7003 if(GetTypeId() == TYPEID_PLAYER
)
7005 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7006 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7008 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7009 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7010 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7011 if (spellInfo
->CasterAuraState
== flag
)
7012 CastSpell(this, itr
->first
, true, NULL
);
7019 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7021 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7022 Unit::AuraMap
& tAuras
= GetAuras();
7023 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7025 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7026 if (spellProto
->CasterAuraState
== flag
)
7028 // exceptions (applied at state but not removed at state change)
7030 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7045 Unit
*Unit::GetOwner() const
7047 uint64 ownerid
= GetOwnerGUID();
7050 return ObjectAccessor::GetUnit(*this, ownerid
);
7053 Unit
*Unit::GetCharmer() const
7055 if(uint64 charmerid
= GetCharmerGUID())
7056 return ObjectAccessor::GetUnit(*this, charmerid
);
7060 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7062 uint64 guid
= GetCharmerOrOwnerGUID();
7063 if(IS_PLAYER_GUID(guid
))
7064 return ObjectAccessor::GetPlayer(*this, guid
);
7066 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7069 Pet
* Unit::GetPet() const
7071 if(uint64 pet_guid
= GetPetGUID())
7073 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7076 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7077 const_cast<Unit
*>(this)->SetPet(0);
7083 Unit
* Unit::GetCharm() const
7085 if(uint64 charm_guid
= GetCharmGUID())
7087 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7090 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7091 const_cast<Unit
*>(this)->SetCharm(0);
7097 void Unit::SetPet(Pet
* pet
)
7099 SetUInt64Value(UNIT_FIELD_SUMMON
,pet
? pet
->GetGUID() : 0);
7101 // FIXME: hack, speed must be set only at follow
7103 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7104 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
7107 void Unit::SetCharm(Unit
* charmed
)
7109 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7112 void Unit::UnsummonAllTotems()
7114 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7119 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7120 if (OldTotem
&& OldTotem
->isTotem())
7121 ((Totem
*)OldTotem
)->UnSummon();
7125 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7128 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7129 data
.append(pVictim
->GetPackGUID());
7130 data
.append(GetPackGUID());
7131 data
<< uint32(SpellID
);
7132 data
<< uint32(Damage
);
7133 data
<< uint8(critical
? 1 : 0);
7134 data
<< uint8(0); // unused in client?
7135 SendMessageToSet(&data
, true);
7138 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7140 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7141 data
.append(pVictim
->GetPackGUID());
7142 data
.append(GetPackGUID());
7143 data
<< uint32(SpellID
);
7144 data
<< uint32(powertype
);
7145 data
<< uint32(Damage
);
7146 //data << uint8(critical ? 1 : 0); // removed in 2.4.0
7147 SendMessageToSet(&data
, true);
7150 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7152 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7155 int32 BonusDamage
= 0;
7156 if( GetTypeId()==TYPEID_UNIT
)
7158 // Pets just add their bonus damage to their spell damage
7159 // note that their spell damage is just gain of their own auras
7160 if (((Creature
*)this)->isPet())
7162 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7164 // For totems get damage bonus from owner (statue isn't totem in fact)
7165 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7167 if(Unit
* owner
= GetOwner())
7168 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7173 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7175 // Taken/Done fixed damage bonus auras
7176 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7177 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7179 // Damage over Time spells bonus calculation
7180 float DotFactor
= 1.0f
;
7181 if(damagetype
== DOT
)
7183 int32 DotDuration
= GetSpellDuration(spellProto
);
7187 if(DotDuration
> 30000) DotDuration
= 30000;
7188 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7190 for(int j
= 0; j
< 3; j
++)
7192 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7193 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7194 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7201 if(spellProto
->EffectAmplitude
[x
] != 0)
7202 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7205 DoneAdvertisedBenefit
/= DotTicks
;
7206 TakenAdvertisedBenefit
/= DotTicks
;
7211 // Taken/Done total percent damage auras
7212 float DoneTotalMod
= 1.0f
;
7213 float TakenTotalMod
= 1.0f
;
7216 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7217 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7219 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7220 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7221 // -1 == any item class (not wand then)
7222 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7223 // 0 == any inventory type (not wand then)
7225 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7229 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7230 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7231 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7232 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7233 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7236 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7237 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7238 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7239 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7241 // .. taken pct: scripted (increases damage of * against targets *)
7242 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7243 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7245 switch((*i
)->GetModifier()->m_miscvalue
)
7248 case 4920: case 4919:
7249 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7250 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7254 // .. taken pct: dummy auras
7255 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7256 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7258 switch((*i
)->GetSpellProto()->SpellIconID
)
7262 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7264 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7266 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7267 if (mod
< (*i
)->GetModifier()->m_amount
)
7268 mod
= (*i
)->GetModifier()->m_amount
;
7269 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7274 for(int j
=0;j
<3;j
++)
7276 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7278 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7286 // Distribute Damage over multiple effects, reduce by AoE
7287 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7289 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7290 for(int j
= 0; j
< 3; ++j
)
7292 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7293 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7300 switch(spellProto
->SpellFamilyName
)
7302 case SPELLFAMILY_MAGE
:
7303 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7304 if(spellProto
->Id
==12654)
7309 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7311 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7312 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7313 TakenTotalMod
*= 3.0f
;
7315 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7316 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7318 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7319 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7321 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7322 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7325 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7328 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7332 // Arcane Missiles triggered spell
7333 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7337 // Blizzard triggered spell
7338 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7343 case SPELLFAMILY_WARLOCK
:
7345 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7347 CastingTime
= 2800; // 80% from +shadow damage
7348 DoneTotalMod
= 1.0f
;
7349 TakenTotalMod
= 1.0f
;
7352 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7354 CastingTime
= 3360; // 96% from +shadow damage
7355 DoneTotalMod
= 1.0f
;
7356 TakenTotalMod
= 1.0f
;
7358 // Soul Fire - 115% of Fire Damage
7359 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7363 // Curse of Agony - 120% of Shadow Damage
7364 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7368 // Drain Mana - 0% of Shadow Damage
7369 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7373 // Drain Soul 214.3%
7374 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7379 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7381 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7383 // Unstable Affliction - 180%
7384 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7389 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7394 case SPELLFAMILY_PALADIN
:
7395 // Consecration - 95% of Holy Damage
7396 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7401 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7402 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7404 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7405 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7407 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7408 CastingTime
= uint32(wspeed
*3500*0.102f
);
7410 CastingTime
= uint32(wspeed
*3500*0.098f
);
7412 // Judgement of Righteousness - 73%
7413 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7417 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7418 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7423 // Holy shield - 5% of Holy Damage
7424 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7428 // Blessing of Sanctuary - 0%
7429 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7433 // Seal of Righteousness trigger - already computed for parent spell
7434 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7439 case SPELLFAMILY_SHAMAN
:
7441 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7443 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7444 CastingTime
= 749; // ignore CastingTime and use as modifier
7445 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7446 CastingTime
= 280; // ignore CastingTime and use as modifier
7447 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7448 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7450 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7451 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7452 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7454 case SPELLFAMILY_PRIEST
:
7455 // Mana Burn - 0% of Shadow Damage
7456 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7460 // Mind Flay - 59% of Shadow Damage
7461 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7465 // Holy Fire - 86.71%, DoT - 16.5%
7466 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7468 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7469 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7471 // Shadowguard - 28% per charge
7472 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7476 // Touch of Weakeness - 10%
7477 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7481 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7482 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7487 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7492 case SPELLFAMILY_DRUID
:
7493 // Hurricane triggered spell
7494 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7499 case SPELLFAMILY_WARRIOR
:
7500 case SPELLFAMILY_HUNTER
:
7501 case SPELLFAMILY_ROGUE
:
7508 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7510 // Spellmod SpellDamage
7511 float SpellModSpellDamage
= 100.0f
;
7513 if(Player
* modOwner
= GetSpellModOwner())
7514 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7516 SpellModSpellDamage
/= 100.0f
;
7518 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7519 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7521 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7523 // Add flat bonus from spell damage versus
7524 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7526 // apply spellmod to Done damage
7527 if(Player
* modOwner
= GetSpellModOwner())
7528 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7530 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7532 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7533 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7535 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7538 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7540 int32 DoneAdvertisedBenefit
= 0;
7543 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7544 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7545 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7546 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7547 // -1 == any item class (not wand then)
7548 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7549 // 0 == any inventory type (not wand then)
7550 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7552 if (GetTypeId() == TYPEID_PLAYER
)
7554 // Damage bonus from stats
7555 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7556 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7558 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7560 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7561 uint8 eff
= (*i
)->GetEffIndex();
7563 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7564 Stats usedStat
= STAT_INTELLECT
;
7565 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7566 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7568 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7571 // ... and attack power
7572 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7573 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7574 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7575 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7578 return DoneAdvertisedBenefit
;
7581 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7583 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7585 int32 TakenAdvertisedBenefit
= 0;
7586 // ..done (for creature type by mask) in taken
7587 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7588 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7589 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7590 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7593 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7594 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7595 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7596 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7598 return TakenAdvertisedBenefit
;
7601 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7603 // not criting spell
7604 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7607 float crit_chance
= 0.0f
;
7608 switch(spellProto
->DmgClass
)
7610 case SPELL_DAMAGE_CLASS_NONE
:
7612 case SPELL_DAMAGE_CLASS_MAGIC
:
7614 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7616 // For other schools
7617 else if (GetTypeId() == TYPEID_PLAYER
)
7618 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7621 crit_chance
= m_baseSpellCritChance
;
7622 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7625 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7627 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7628 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7629 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7630 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7631 // Modify by player victim resilience
7632 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7633 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7634 // scripted (increase crit chance ... against ... target by x%
7635 if(pVictim
->isFrozen()) // Shatter
7637 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7638 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7640 switch((*i
)->GetModifier()->m_miscvalue
)
7642 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7643 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7644 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7645 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7646 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7653 case SPELL_DAMAGE_CLASS_MELEE
:
7654 case SPELL_DAMAGE_CLASS_RANGED
:
7658 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7659 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7660 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7668 // only players use intelligence for critical chance computations
7669 if(Player
* modOwner
= GetSpellModOwner())
7670 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7672 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7673 if (roll_chance_f(crit_chance
))
7678 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7680 // Calculate critical bonus
7682 switch(spellProto
->DmgClass
)
7684 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7685 case SPELL_DAMAGE_CLASS_RANGED
:
7686 // TODO: write here full calculation for melee/ranged spells
7687 crit_bonus
= damage
;
7690 crit_bonus
= damage
/ 2; // for spells is 50%
7694 // adds additional damage to crit_bonus (from talents)
7695 if(Player
* modOwner
= GetSpellModOwner())
7696 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7700 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7701 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7705 damage
+= crit_bonus
;
7710 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7712 // For totems get healing bonus from owner (statue isn't totem in fact)
7713 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7714 if(Unit
* owner
= GetOwner())
7715 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7719 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7720 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7721 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7722 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7725 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7726 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7729 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7731 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7732 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7734 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7735 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7737 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
7740 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7741 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7743 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7744 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7749 float ActualBenefit
= 0.0f
;
7751 if (AdvertisedBenefit
!= 0)
7753 // Healing over Time spells
7754 float DotFactor
= 1.0f
;
7755 if(damagetype
== DOT
)
7757 int32 DotDuration
= GetSpellDuration(spellProto
);
7761 if(DotDuration
> 30000) DotDuration
= 30000;
7762 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7764 for(int j
= 0; j
< 3; j
++)
7766 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7767 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7768 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7775 if(spellProto
->EffectAmplitude
[x
] != 0)
7776 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7778 AdvertisedBenefit
/= DotTicks
;
7782 // distribute healing to all effects, reduce AoE damage
7783 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7785 // 0% bonus for damage and healing spells for leech spells from healing bonus
7786 for(int j
= 0; j
< 3; ++j
)
7788 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7789 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7797 switch (spellProto
->SpellFamilyName
)
7799 case SPELLFAMILY_SHAMAN
:
7800 // Healing stream from totem (add 6% per tick from hill bonus owner)
7801 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7803 // Earth Shield 30% per charge
7804 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7807 case SPELLFAMILY_DRUID
:
7809 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7811 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7812 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7814 // Tranquility triggered spell
7815 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7818 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7821 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7823 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7824 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7827 case SPELLFAMILY_PRIEST
:
7829 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7832 case SPELLFAMILY_PALADIN
:
7833 // Seal and Judgement of Light
7834 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7837 case SPELLFAMILY_WARRIOR
:
7838 case SPELLFAMILY_ROGUE
:
7839 case SPELLFAMILY_HUNTER
:
7844 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7846 // Spellmod SpellDamage
7847 float SpellModSpellDamage
= 100.0f
;
7849 if(Player
* modOwner
= GetSpellModOwner())
7850 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7852 SpellModSpellDamage
/= 100.0f
;
7854 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7857 // use float as more appropriate for negative values and percent applying
7858 float heal
= healamount
+ ActualBenefit
;
7860 // TODO: check for ALL/SPELLS type
7861 // Healing done percent
7862 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7863 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7864 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7866 // apply spellmod to Done amount
7867 if(Player
* modOwner
= GetSpellModOwner())
7868 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7870 // Healing Wave cast
7871 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7873 // Search for Healing Way on Victim (stack up to 3 time)
7875 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7876 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7877 if((*itr
)->GetId() == 29203)
7878 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7881 heal
= heal
* (100 + pctMod
) / 100;
7884 // Healing taken percent
7885 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7887 heal
*= (100.0f
+ minval
) / 100.0f
;
7889 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7891 heal
*= (100.0f
+ maxval
) / 100.0f
;
7893 if (heal
< 0) heal
= 0;
7895 return uint32(heal
);
7898 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7900 int32 AdvertisedBenefit
= 0;
7902 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7903 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7904 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7905 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7907 // Healing bonus of spirit, intellect and strength
7908 if (GetTypeId() == TYPEID_PLAYER
)
7910 // Healing bonus from stats
7911 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7912 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7914 // stat used dependent from misc value (stat index)
7915 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7916 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7919 // ... and attack power
7920 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7921 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7922 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7923 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7925 return AdvertisedBenefit
;
7928 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7930 int32 AdvertisedBenefit
= 0;
7931 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7932 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7933 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7934 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7935 return AdvertisedBenefit
;
7938 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7940 // no charges dependent checks
7941 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7942 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7943 if(itr
->type
& shoolMask
)
7946 // charges dependent checks
7947 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7948 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7950 if(itr
->type
& shoolMask
)
7954 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7955 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
7957 if((*auraItr
)->GetId()==itr
->spellId
)
7959 if((*auraItr
)->m_procCharges
> 0)
7961 --(*auraItr
)->m_procCharges
;
7962 if((*auraItr
)->m_procCharges
==0)
7963 RemoveAurasDueToSpell(itr
->spellId
);
7976 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
7983 //FIX ME this hack: don't get feared if stunned
7984 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
7986 if ( hasUnitState(UNIT_STAT_STUNNED
) )
7990 // not have spells with charges currently
7991 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
7992 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
7993 if(itr
->type
== spellInfo
->Dispel
)
7996 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
7998 // not have spells with charges currently
7999 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8000 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8001 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8002 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8006 // charges dependent checks
8008 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8009 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8011 if(itr
->type
== spellInfo
->Mechanic
)
8015 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8016 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8018 if((*auraItr
)->GetId()==itr
->spellId
)
8020 if((*auraItr
)->m_procCharges
> 0)
8022 --(*auraItr
)->m_procCharges
;
8023 if((*auraItr
)->m_procCharges
==0)
8024 RemoveAurasDueToSpell(itr
->spellId
);
8037 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8039 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8040 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8041 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8042 if(itr
->type
== effect
)
8045 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8046 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8047 if(itr
->type
== mechanic
)
8053 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8058 uint32 family
= spellInfo
->SpellFamilyName
;
8059 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8061 if((family
== 5 && flags
== 256) || //Searing Pain
8062 (family
== 6 && flags
== 8192) || //Mind Blast
8063 (family
== 11 && flags
== 1048576)) //Earth Shock
8069 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8077 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8079 // Taken/Done fixed damage bonus auras
8080 int32 DoneFlatBenefit
= 0;
8081 int32 TakenFlatBenefit
= 0;
8083 // ..done (for creature type by mask) in taken
8084 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8085 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8086 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8087 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8090 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8092 // ..done (base at attack power for marked target and base at attack power for creature type)
8094 if(attType
== RANGED_ATTACK
)
8096 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8098 // ..done (base at attack power and creature type)
8099 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8100 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8101 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8102 APbonus
+= (*i
)->GetModifier()->m_amount
;
8106 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8108 // ..done (base at attack power and creature type)
8109 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8110 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8111 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8112 APbonus
+= (*i
)->GetModifier()->m_amount
;
8115 if (APbonus
!=0) // Can be negative
8117 bool normalized
= false;
8120 for (uint8 i
= 0; i
<3;i
++)
8122 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8130 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8134 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8135 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8136 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8137 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8139 if(attType
!=RANGED_ATTACK
)
8140 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8142 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8144 // Done/Taken total percent damage auras
8145 float DoneTotalMod
= 1;
8146 float TakenTotalMod
= 1;
8149 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8150 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8152 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8153 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8154 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8155 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8158 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8159 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8160 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8161 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8163 // .. taken pct: dummy auras
8164 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8165 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8167 switch((*i
)->GetSpellProto()->SpellIconID
)
8171 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8173 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8175 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8176 if (mod
< (*i
)->GetModifier()->m_amount
)
8177 mod
= (*i
)->GetModifier()->m_amount
;
8178 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8183 if(spellProto
==NULL
)
8185 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8186 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8187 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8192 // .. taken pct: class scripts
8193 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8194 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8196 switch((*i
)->GetMiscValue())
8198 case 6427: case 6428: // Dirty Deeds
8199 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8201 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8202 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8204 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8208 // effect 0 have expected value but in negative state
8209 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8215 if(attType
!= RANGED_ATTACK
)
8217 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8218 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8219 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8223 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8224 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8225 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8228 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8230 // apply spellmod to Done damage
8233 if(Player
* modOwner
= GetSpellModOwner())
8234 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8237 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8239 // bonus result can be negative
8240 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8243 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8247 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8250 if(itr
->type
== type
)
8252 m_spellImmune
[op
].erase(itr
);
8253 next
= m_spellImmune
[op
].begin();
8257 Immune
.spellId
= spellId
;
8259 m_spellImmune
[op
].push_back(Immune
);
8263 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8265 if(itr
->spellId
== spellId
)
8267 m_spellImmune
[op
].erase(itr
);
8275 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8277 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8279 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8280 RemoveAurasWithDispelType(type
);
8283 float Unit::GetWeaponProcChance() const
8285 // normalized proc chance for weapon attack speed
8287 if(isAttackReady(BASE_ATTACK
))
8288 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8289 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8290 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8294 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8296 // proc per minute chance calculation
8297 if (PPM
<= 0) return 0.0f
;
8298 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8302 void Unit::Mount(uint32 mount
)
8307 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8309 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8311 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8314 if(GetTypeId() == TYPEID_PLAYER
)
8316 Pet
* pet
= GetPet();
8319 if(pet
->isControlled())
8321 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8322 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8325 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8328 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8332 void Unit::Unmount()
8337 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8339 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8340 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8342 // only resummon old pet if the player is already added to a map
8343 // this prevents adding a pet to a not created map which would otherwise cause a crash
8344 // (it could probably happen when logging in after a previous crash)
8345 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8347 Pet
* NewPet
= new Pet
;
8348 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8351 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8355 void Unit::SetInCombatWith(Unit
* enemy
)
8357 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8360 SetInCombatState(true);
8365 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8367 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8368 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8370 SetInCombatState(true);
8374 SetInCombatState(false);
8377 void Unit::SetInCombatState(bool PvP
)
8379 // only alive units can be in combat
8384 m_CombatTimer
= 5000;
8385 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8387 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8388 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8391 void Unit::ClearInCombat()
8394 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8396 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8397 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8399 // Player's state will be cleared in Player::UpdateContestedPvP
8400 if(GetTypeId()!=TYPEID_PLAYER
)
8401 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8404 bool Unit::isTargetableForAttack() const
8406 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8409 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8412 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8415 int32
Unit::ModifyHealth(int32 dVal
)
8422 int32 curHealth
= (int32
)GetHealth();
8424 int32 val
= dVal
+ curHealth
;
8431 int32 maxHealth
= (int32
)GetMaxHealth();
8436 gain
= val
- curHealth
;
8438 else if(curHealth
!= maxHealth
)
8440 SetHealth(maxHealth
);
8441 gain
= maxHealth
- curHealth
;
8447 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8454 int32 curPower
= (int32
)GetPower(power
);
8456 int32 val
= dVal
+ curPower
;
8463 int32 maxPower
= (int32
)GetMaxPower(power
);
8467 SetPower(power
,val
);
8468 gain
= val
- curPower
;
8470 else if(curPower
!= maxPower
)
8472 SetPower(power
,maxPower
);
8473 gain
= maxPower
- curPower
;
8479 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8484 // Always can see self
8488 // player visible for other player if not logout and at same transport
8489 // including case when player is out of world
8490 bool at_same_transport
=
8491 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8492 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8493 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8494 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8497 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8500 // forbidden to seen (at GM respawn command)
8501 if(m_Visibility
==VISIBILITY_RESPAWN
)
8504 // always seen by owner
8505 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8508 // Grid dead/alive checks
8509 if( u
->GetTypeId()==TYPEID_PLAYER
)
8511 // non visible at grid for any stealth state
8512 if(!IsVisibleInGridForPlayer((Player
*)u
))
8515 // if player is dead then he can't detect anyone in any cases
8521 // all dead creatures/players not visible for any creatures
8522 if(!u
->isAlive() || !isAlive())
8526 // different visible distance checks
8527 if(u
->isInFlight()) // what see player in flight
8529 // use object grey distance for all (only see objects any way)
8530 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8533 else if(!isAlive()) // distance for show body
8535 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8538 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8540 if(u
->GetTypeId()==TYPEID_PLAYER
)
8542 // Players far than max visible distance for player or not in our map are not visible too
8543 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8548 // Units far than max visible distance for creature or not in our map are not visible too
8549 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8553 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8555 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8556 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8559 else // distance for show creature
8561 // Units far than max visible distance for creature or not in our map are not visible too
8562 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8566 // Visible units, always are visible for all units, except for units under invisibility
8567 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8570 // GMs see any players, not higher GMs and all units
8571 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8573 if(GetTypeId() == TYPEID_PLAYER
)
8574 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8579 // non faction visibility non-breakable for non-GMs
8580 if (m_Visibility
== VISIBILITY_OFF
)
8584 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8586 // detectable invisibility case
8588 // Invisible units, always are visible for units under same invisibility type
8589 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8590 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8591 u
->canDetectInvisibilityOf(this) ||
8592 // Units that can detect invisibility always are visible for units that can be detected
8593 canDetectInvisibilityOf(u
) ))
8598 // special cases for always overwrite invisibility/stealth
8599 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8602 if (!u
->IsHostileTo(this))
8604 // 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)
8605 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8607 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8610 // else apply same rules as for hostile case (detecting check for stealth)
8616 // Hunter mark functionality
8617 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8618 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8619 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8622 // else apply detecting check for stealth
8625 // none other cases for detect invisibility, so invisible
8629 // else apply stealth detecting check
8632 // unit got in stealth in this moment and must ignore old detected state
8633 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8636 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8637 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8640 // NOW ONLY STEALTH CASE
8642 // stealth and detected and visible for some seconds
8643 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8646 //if in non-detect mode then invisible for unit
8652 // If is attacked then stealth is lost, some creature can use stealth too
8653 if( !getAttackers().empty() )
8656 // If there is collision rogue is seen regardless of level difference
8657 // TODO: check sizes in DB
8658 float distance
= GetDistance(u
);
8659 if (distance
< 0.24f
)
8662 //If a mob or player is stunned he will not be able to detect stealth
8663 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8666 // Creature can detect target only in aggro radius
8667 if(u
->GetTypeId() != TYPEID_PLAYER
)
8669 //Always invisible from back and out of aggro range
8670 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8676 //Always invisible from back
8677 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8682 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8683 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8685 //Calculation if target is in front
8687 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8688 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8690 //Visible distance is modified by
8691 //-Level Diff (every level diff = 1.0f in visible distance)
8692 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8694 //This allows to check talent tree and will add addition stealth dependent on used points)
8695 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8699 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8700 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8701 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8703 if(distance
> visibleDistance
)
8707 // Now check is target visible with LoS
8709 u
->GetPosition(ox
,oy
,oz
);
8710 return IsWithinLOS(ox
,oy
,oz
);
8713 void Unit::SetVisibility(UnitVisibility x
)
8719 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8721 if(GetTypeId()==TYPEID_PLAYER
)
8722 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8724 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8728 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8730 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8732 for(uint32 i
= 0; i
< 10; ++i
)
8734 if(((1 << i
) & mask
)==0)
8737 // find invisibility level
8738 uint32 invLevel
= 0;
8739 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8740 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8741 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8742 invLevel
= (*itr
)->GetModifier()->m_amount
;
8744 // find invisibility detect level
8745 uint32 detectLevel
= 0;
8746 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8747 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8748 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8749 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8751 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8753 detectLevel
= ((Player
*)this)->GetDrunkValue();
8756 if(invLevel
<= detectLevel
)
8764 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8766 int32 main_speed_mod
= 0;
8767 float stack_bonus
= 1.0f
;
8768 float non_stack_bonus
= 1.0f
;
8776 if (IsMounted()) // Use on mount auras
8778 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8779 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8780 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8784 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8785 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8786 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8794 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8801 if (IsMounted()) // Use on mount auras
8802 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8803 else // Use not mount (shapeshift for example) auras (should stack)
8804 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8805 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8806 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8812 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8816 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8817 // now we ready for speed calculation
8818 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8826 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8827 // TODO: possible affect only on MOVE_RUN
8828 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8830 // Use speed from aura
8831 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8832 if (speed
> max_speed
)
8841 // Apply strongest slow aura mod to speed
8842 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8844 speed
*=(100.0f
+ slow
)/100.0f
;
8845 SetSpeed(mtype
, speed
, forced
);
8848 float Unit::GetSpeed( UnitMoveType mtype
) const
8850 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8853 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8858 // Update speed only on change
8859 if (m_speed_rate
[mtype
] == rate
)
8862 m_speed_rate
[mtype
] = rate
;
8864 propagateSpeedChange();
8866 // Send speed change packet only for player
8867 if (GetTypeId()!=TYPEID_PLAYER
)
8876 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8879 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8882 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8885 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8888 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8891 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8894 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8897 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8900 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8904 data
.append(GetPackGUID());
8905 data
<< uint32(0); //movement flags
8906 data
<< uint8(0); //unk
8907 data
<< uint32(getMSTime());
8908 data
<< float(GetPositionX());
8909 data
<< float(GetPositionY());
8910 data
<< float(GetPositionZ());
8911 data
<< float(GetOrientation());
8912 data
<< uint32(0); //flag unk
8913 data
<< float(GetSpeed(mtype
));
8914 SendMessageToSet( &data
, true );
8918 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8919 // and do it only for real sent packets and use run for run/mounted as client expected
8920 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8924 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8927 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8930 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8933 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8936 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8939 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8942 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8945 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8948 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8951 data
.append(GetPackGUID());
8953 if (mtype
== MOVE_RUN
)
8954 data
<< uint8(0); // new 2.1.0
8955 data
<< float(GetSpeed(mtype
));
8956 SendMessageToSet( &data
, true );
8958 if(Pet
* pet
= GetPet())
8959 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
8962 void Unit::SetHover(bool on
)
8965 CastSpell(this,11010,true);
8967 RemoveAurasDueToSpell(11010);
8970 void Unit::setDeathState(DeathState s
)
8972 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
8976 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
8978 if(IsNonMeleeSpellCasted(false))
8979 InterruptNonMeleeSpells(false);
8984 RemoveAllAurasOnDeath();
8985 UnsummonAllTotems();
8987 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
8988 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
8989 // remove aurastates allowing special moves
8990 ClearAllReactives();
8991 ClearDiminishings();
8993 else if(s
== JUST_ALIVED
)
8995 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
8998 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9000 //_ApplyAllAuraMods();
9005 /*########################################
9007 ######## AGGRO SYSTEM ########
9009 ########################################*/
9010 bool Unit::CanHaveThreatList() const
9012 // only creatures can have threat list
9013 if( GetTypeId() != TYPEID_UNIT
)
9016 // only alive units can have threat list
9020 // pets and totems can not have threat list
9021 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() )
9027 //======================================================================
9029 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9031 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9034 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9036 return threat
* m_threatModifier
[school
];
9039 //======================================================================
9041 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9043 // Only mobs can manage threat lists
9044 if(CanHaveThreatList())
9045 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9048 //======================================================================
9050 void Unit::DeleteThreatList()
9052 m_ThreatManager
.clearReferences();
9055 //======================================================================
9057 void Unit::TauntApply(Unit
* taunter
)
9059 assert(GetTypeId()== TYPEID_UNIT
);
9061 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9064 if(!CanHaveThreatList())
9067 Unit
*target
= getVictim();
9068 if(target
&& target
== taunter
)
9071 SetInFront(taunter
);
9072 if (((Creature
*)this)->AI())
9073 ((Creature
*)this)->AI()->AttackStart(taunter
);
9075 m_ThreatManager
.tauntApply(taunter
);
9078 //======================================================================
9080 void Unit::TauntFadeOut(Unit
*taunter
)
9082 assert(GetTypeId()== TYPEID_UNIT
);
9084 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9087 if(!CanHaveThreatList())
9090 Unit
*target
= getVictim();
9091 if(!target
|| target
!= taunter
)
9094 if(m_ThreatManager
.isThreatListEmpty())
9096 if(((Creature
*)this)->AI())
9097 ((Creature
*)this)->AI()->EnterEvadeMode();
9101 m_ThreatManager
.tauntFadeOut(taunter
);
9102 target
= m_ThreatManager
.getHostilTarget();
9104 if (target
&& target
!= taunter
)
9107 if (((Creature
*)this)->AI())
9108 ((Creature
*)this)->AI()->AttackStart(target
);
9112 //======================================================================
9114 bool Unit::SelectHostilTarget()
9116 //function provides main threat functionality
9117 //next-victim-selection algorithm and evade mode are called
9118 //threat list sorting etc.
9120 assert(GetTypeId()== TYPEID_UNIT
);
9121 Unit
* target
= NULL
;
9123 //This function only useful once AI has been initialized
9124 if (!((Creature
*)this)->AI())
9127 if(!m_ThreatManager
.isThreatListEmpty())
9129 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9131 target
= m_ThreatManager
.getHostilTarget();
9137 if(!hasUnitState(UNIT_STAT_STUNNED
))
9139 ((Creature
*)this)->AI()->AttackStart(target
);
9143 // no target but something prevent go to evade mode
9144 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9147 // last case when creature don't must go to evade mode:
9148 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9149 // for example at owner command to pet attack some far away creature
9150 // Note: creature not have targeted movement generator but have attacker in this case
9151 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9153 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9155 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9160 // enter in evade mode in other case
9161 ((Creature
*)this)->AI()->EnterEvadeMode();
9166 //======================================================================
9167 //======================================================================
9168 //======================================================================
9170 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9172 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9174 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9176 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9177 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9178 level
= spellProto
->maxLevel
;
9180 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9181 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9182 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9183 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9184 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9186 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9187 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9188 int32 value
= basePoints
+ randvalue
;
9190 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9191 value
+= (int32
)(comboDamage
* comboPoints
);
9193 if(Player
* modOwner
= GetSpellModOwner())
9195 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9196 switch(effect_index
)
9199 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9202 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9205 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9210 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9211 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9212 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9213 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9218 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9220 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9222 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9224 int32 minduration
= GetSpellDuration(spellProto
);
9225 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9229 if( minduration
!= -1 && minduration
!= maxduration
)
9230 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9232 duration
= minduration
;
9236 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9237 // Find total mod value (negative bonus)
9238 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9239 // Find max mod (negative bonus)
9240 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9242 int32 durationMod
= 0;
9243 // Select strongest negative mod
9244 if (durationMod_always
> durationMod_not_stack
)
9245 durationMod
= durationMod_not_stack
;
9247 durationMod
= durationMod_always
;
9249 if (durationMod
!= 0)
9250 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9252 if (duration
< 0) duration
= 0;
9258 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9260 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9262 if(i
->DRGroup
!= group
)
9266 return DIMINISHING_LEVEL_1
;
9269 return DIMINISHING_LEVEL_1
;
9271 // If last spell was casted more than 15 seconds ago - reset the count.
9272 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9274 i
->hitCount
= DIMINISHING_LEVEL_1
;
9275 return DIMINISHING_LEVEL_1
;
9277 // or else increase the count.
9280 return DiminishingLevels(i
->hitCount
);
9283 return DIMINISHING_LEVEL_1
;
9286 void Unit::IncrDiminishing(DiminishingGroup group
)
9288 // Checking for existing in the table
9289 bool IsExist
= false;
9290 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9292 if(i
->DRGroup
!= group
)
9296 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9303 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9306 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9308 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9311 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9312 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9314 // test pet/charm masters instead pets/charmeds
9315 Unit
const* targetOwner
= GetCharmerOrOwner();
9316 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9318 Unit
const* target
= targetOwner
? targetOwner
: this;
9319 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9321 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9327 // Some diminishings applies to mobs too (for example, Stun)
9328 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9330 DiminishingLevels diminish
= Level
;
9333 case DIMINISHING_LEVEL_1
: break;
9334 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9335 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9336 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9341 duration
= int32(duration
* mod
);
9344 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9346 // Checking for existing in the table
9347 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9349 if(i
->DRGroup
!= group
)
9352 i
->hitTime
= getMSTime();
9363 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9365 return ObjectAccessor::GetUnit(object
,guid
);
9368 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9370 return isVisibleForOrDetect(u
,false,inVisibleList
);
9373 uint32
Unit::GetCreatureType() const
9375 if(GetTypeId() == TYPEID_PLAYER
)
9377 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9378 if(ssEntry
&& ssEntry
->creatureType
> 0)
9379 return ssEntry
->creatureType
;
9381 return CREATURE_TYPE_HUMANOID
;
9384 return ((Creature
*)this)->GetCreatureInfo()->type
;
9387 /*#######################################
9389 ######## STAT SYSTEM ########
9391 #######################################*/
9393 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9395 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9397 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9403 switch(modifierType
)
9407 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9411 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9414 val
= (100.0f
+ amount
) / 100.0f
;
9415 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9422 if(!CanModifyStats())
9427 case UNIT_MOD_STAT_STRENGTH
:
9428 case UNIT_MOD_STAT_AGILITY
:
9429 case UNIT_MOD_STAT_STAMINA
:
9430 case UNIT_MOD_STAT_INTELLECT
:
9431 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9433 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9434 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9438 case UNIT_MOD_FOCUS
:
9439 case UNIT_MOD_ENERGY
:
9440 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9442 case UNIT_MOD_RESISTANCE_HOLY
:
9443 case UNIT_MOD_RESISTANCE_FIRE
:
9444 case UNIT_MOD_RESISTANCE_NATURE
:
9445 case UNIT_MOD_RESISTANCE_FROST
:
9446 case UNIT_MOD_RESISTANCE_SHADOW
:
9447 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9449 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9450 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9452 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9453 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9454 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9463 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9465 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9467 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9471 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9474 return m_auraModifiersGroup
[unitMod
][modifierType
];
9477 float Unit::GetTotalStatValue(Stats stat
) const
9479 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9481 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9484 // value = ((base_value * base_pct) + total_value) * total_pct
9485 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9486 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9487 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9488 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9493 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9495 if(unitMod
>= UNIT_MOD_END
)
9497 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9501 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9504 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9505 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9506 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9507 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9512 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9514 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9518 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9519 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9520 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9521 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9522 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9523 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9532 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9534 Stats stat
= STAT_STRENGTH
;
9538 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9539 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9540 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9541 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9542 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9551 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9553 Powers power
= POWER_MANA
;
9557 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9558 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9559 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9560 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9561 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9570 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9572 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9574 float val
= GetTotalAuraModValue(unitMod
);
9581 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9583 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9586 return m_weaponDamage
[attType
][type
];
9589 void Unit::SetLevel(uint32 lvl
)
9591 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9594 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9595 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9598 void Unit::SetHealth(uint32 val
)
9600 uint32 maxHealth
= GetMaxHealth();
9604 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9607 if(GetTypeId() == TYPEID_PLAYER
)
9609 if(((Player
*)this)->GetGroup())
9610 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9612 else if(((Creature
*)this)->isPet())
9614 Pet
*pet
= ((Pet
*)this);
9615 if(pet
->isControlled())
9617 Unit
*owner
= GetOwner();
9618 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9619 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9624 void Unit::SetMaxHealth(uint32 val
)
9626 uint32 health
= GetHealth();
9627 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9630 if(GetTypeId() == TYPEID_PLAYER
)
9632 if(((Player
*)this)->GetGroup())
9633 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9635 else if(((Creature
*)this)->isPet())
9637 Pet
*pet
= ((Pet
*)this);
9638 if(pet
->isControlled())
9640 Unit
*owner
= GetOwner();
9641 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9642 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9650 void Unit::SetPower(Powers power
, uint32 val
)
9652 uint32 maxPower
= GetMaxPower(power
);
9656 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9659 if(GetTypeId() == TYPEID_PLAYER
)
9661 if(((Player
*)this)->GetGroup())
9662 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9664 else if(((Creature
*)this)->isPet())
9666 Pet
*pet
= ((Pet
*)this);
9667 if(pet
->isControlled())
9669 Unit
*owner
= GetOwner();
9670 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9671 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9674 // Update the pet's character sheet with happiness damage bonus
9675 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9677 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9682 void Unit::SetMaxPower(Powers power
, uint32 val
)
9684 uint32 cur_power
= GetPower(power
);
9685 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9688 if(GetTypeId() == TYPEID_PLAYER
)
9690 if(((Player
*)this)->GetGroup())
9691 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9693 else if(((Creature
*)this)->isPet())
9695 Pet
*pet
= ((Pet
*)this);
9696 if(pet
->isControlled())
9698 Unit
*owner
= GetOwner();
9699 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9700 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9705 SetPower(power
, val
);
9708 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9710 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9713 if(GetTypeId() == TYPEID_PLAYER
)
9715 if(((Player
*)this)->GetGroup())
9716 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_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_CUR_POWER
);
9730 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9732 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9735 if(GetTypeId() == TYPEID_PLAYER
)
9737 if(((Player
*)this)->GetGroup())
9738 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9740 else if(((Creature
*)this)->isPet())
9742 Pet
*pet
= ((Pet
*)this);
9743 if(pet
->isControlled())
9745 Unit
*owner
= GetOwner();
9746 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9747 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9752 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9754 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9756 tAuraProcTriggerDamage
.push_back(aura
);
9758 tAuraProcTriggerDamage
.remove(aura
);
9761 uint32
Unit::GetCreatePowers( Powers power
) const
9763 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9766 case POWER_MANA
: return GetCreateMana();
9767 case POWER_RAGE
: return 1000;
9768 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9769 case POWER_ENERGY
: return 100;
9770 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9776 void Unit::AddToWorld()
9778 Object::AddToWorld();
9781 void Unit::RemoveFromWorld()
9786 RemoveNotOwnSingleTargetAuras();
9789 Object::RemoveFromWorld();
9792 void Unit::CleanupsBeforeDelete()
9794 if(m_uint32Values
) // only for fully created object
9796 InterruptNonMeleeSpells(true);
9797 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9799 ClearComboPointHolders();
9801 getHostilRefManager().setOnlineOfflineState(false);
9803 RemoveAllGameObjects();
9804 RemoveAllDynObjects();
9805 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9810 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9813 m_charmInfo
= new CharmInfo(charm
);
9817 CharmInfo::CharmInfo(Unit
* unit
)
9818 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9820 for(int i
=0; i
<4; ++i
)
9822 m_charmspells
[i
].spellId
= 0;
9823 m_charmspells
[i
].active
= ACT_DISABLED
;
9827 void CharmInfo::InitPetActionBar()
9829 // the first 3 SpellOrActions are attack, follow and stay
9830 for(uint32 i
= 0; i
< 3; i
++)
9832 PetActionBar
[i
].Type
= ACT_COMMAND
;
9833 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9835 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9836 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9838 for(uint32 i
=0; i
< 4; i
++)
9840 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9841 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9845 void CharmInfo::InitEmptyActionBar()
9847 for(uint32 x
= 1; x
< 10; ++x
)
9849 PetActionBar
[x
].Type
= ACT_CAST
;
9850 PetActionBar
[x
].SpellOrAction
= 0;
9852 PetActionBar
[0].Type
= ACT_COMMAND
;
9853 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9856 void CharmInfo::InitPossessCreateSpells()
9858 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9861 InitEmptyActionBar(); //charm action bar
9863 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9865 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9866 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9868 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9872 void CharmInfo::InitCharmCreateSpells()
9874 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9876 InitEmptyActionBar();
9882 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9884 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9885 m_charmspells
[x
].spellId
= spellId
;
9890 if (IsPassiveSpell(spellId
))
9892 m_unit
->CastSpell(m_unit
, spellId
, true);
9893 m_charmspells
[x
].active
= ACT_PASSIVE
;
9897 ActiveStates newstate
;
9898 bool onlyselfcast
= true;
9899 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9901 if(!spellInfo
) onlyselfcast
= false;
9902 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9904 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9905 onlyselfcast
= false;
9908 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9909 newstate
= ACT_DISABLED
;
9911 newstate
= ACT_CAST
;
9913 AddSpellToAB(0, spellId
, newstate
);
9918 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9920 for(uint8 i
= 0; i
< 10; i
++)
9922 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9924 PetActionBar
[i
].SpellOrAction
= newid
;
9927 if(newstate
== ACT_DECIDE
)
9928 PetActionBar
[i
].Type
= ACT_DISABLED
;
9930 PetActionBar
[i
].Type
= newstate
;
9939 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9941 if(IsPassiveSpell(spellid
))
9944 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9946 if(spellid
== m_charmspells
[x
].spellId
)
9948 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
9953 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
9955 m_petnumber
= petnumber
;
9957 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
9959 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
9962 bool Unit::isFrozen() const
9964 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
9965 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
9966 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
9971 struct ProcTriggeredData
9973 ProcTriggeredData(SpellEntry
const * _spellInfo
, uint32 _spellParam
, Aura
* _triggeredByAura
, uint32 _cooldown
)
9974 : spellInfo(_spellInfo
), spellParam(_spellParam
), triggeredByAura(_triggeredByAura
),
9975 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
9979 SpellEntry
const * spellInfo
;
9981 Aura
* triggeredByAura
;
9982 Unit::spellEffectPair triggeredByAura_SpellPair
;
9986 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
9988 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
9990 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
9992 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
9993 ProcTriggeredList procTriggered
;
9995 AuraList
const& auras
= GetAurasByType(*aur
);
9996 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10000 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
10004 SpellProcEventEntry
const *spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10005 if(!spellProcEvent
)
10007 // used to prevent spam in log about same non-handled spells
10008 static std::set
<uint32
> nonHandledSpellProcSet
;
10010 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10012 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10013 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10016 // spell.dbc use totally different flags, that only can create problems if used.
10020 // Check spellProcEvent data requirements
10021 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10024 // Check if current equipment allows aura to proc
10025 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10027 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10029 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10031 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10034 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10036 // Check if player is wearing shield
10037 Item
*item
= ((Player
*)this)->GetShield(true);
10038 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10043 float chance
= (float)spellProto
->procChance
;
10045 if(Player
* modOwner
= GetSpellModOwner())
10046 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10048 if(!isVictim
&& spellProcEvent
->ppmRate
!= 0)
10050 uint32 WeaponSpeed
= GetAttackTime(attType
);
10051 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10054 if(roll_chance_f(chance
))
10056 uint32 cooldown
= spellProcEvent
->cooldown
;
10058 uint32 i_spell_eff
= (*i
)->GetEffIndex();
10060 int32 i_spell_param
;
10063 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10064 i_spell_param
= procFlag
;
10066 case SPELL_AURA_DUMMY
:
10067 case SPELL_AURA_PRAYER_OF_MENDING
:
10068 case SPELL_AURA_MOD_HASTE
:
10069 i_spell_param
= i_spell_eff
;
10071 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10072 i_spell_param
= (*i
)->GetModifier()->m_miscvalue
;
10075 i_spell_param
= (*i
)->GetModifier()->m_amount
;
10079 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
, cooldown
) );
10083 // Handle effects proceed this time
10084 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10086 // Some auras can be deleted in function called in this loop (except first, ofc)
10087 // Until storing auras in std::multimap to hard check deleting by another way
10088 if(i
!= procTriggered
.begin())
10090 bool found
= false;
10091 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10092 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10093 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10095 if(itr
->second
==i
->triggeredByAura
)
10104 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
);
10105 sLog
.outError("It can be deleted one from early processed auras:");
10106 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10107 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10108 sLog
.outError(" <end of list>");
10113 // save charges existence before processing to prevent crash at access to deleted triggered aura after
10114 bool triggeredByAuraWithCharges
= i
->triggeredByAura
->m_procCharges
> 0;
10116 bool casted
= false;
10119 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10121 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10122 casted
= HandleProcTriggerSpell(pTarget
, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
,attType
,i
->cooldown
);
10125 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10127 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i
->spellParam
, i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10128 uint32 damage
= i
->spellParam
;
10129 SpellNonMeleeDamageLog(pTarget
, i
->spellInfo
->Id
, damage
, true, true);
10133 case SPELL_AURA_DUMMY
:
10135 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10136 casted
= HandleDummyAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10139 case SPELL_AURA_PRAYER_OF_MENDING
:
10141 sLog
.outDebug("ProcDamageAndSpell(mending): casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10143 // aura can be deleted at casts
10144 int32 heal
= i
->triggeredByAura
->GetModifier()->m_amount
;
10145 uint64 caster_guid
= i
->triggeredByAura
->GetCasterGUID();
10148 int32 jumps
= i
->triggeredByAura
->m_procCharges
-1;
10150 // current aura expire
10151 i
->triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10153 // next target selection
10154 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10156 Aura
* aura
= i
->triggeredByAura
;
10158 SpellEntry
const* spellProto
= aura
->GetSpellProto();
10159 uint32 effIdx
= aura
->GetEffIndex();
10162 if (spellProto
->EffectRadiusIndex
[effIdx
])
10163 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10165 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10167 if(Player
* caster
= ((Player
*)aura
->GetCaster()))
10169 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10171 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10173 // aura will applied from caster, but spell casted from current aura holder
10174 SpellModifier
*mod
= new SpellModifier
;
10175 mod
->op
= SPELLMOD_CHARGES
;
10176 mod
->value
= jumps
-5; // negative
10177 mod
->type
= SPELLMOD_FLAT
;
10178 mod
->spellId
= spellProto
->Id
;
10179 mod
->effectId
= effIdx
;
10180 mod
->lastAffected
= NULL
;
10181 mod
->mask
= spellProto
->SpellFamilyFlags
;
10184 caster
->AddSpellMod(mod
, true);
10185 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,aura
,caster
->GetGUID());
10186 caster
->AddSpellMod(mod
, false);
10192 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10196 case SPELL_AURA_MOD_HASTE
:
10198 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10199 casted
= HandleHasteAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10202 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10204 // nothing do, just charges counter
10205 // but count only in case appropriate school damage
10206 casted
= i
->triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10209 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10211 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
10212 casted
= HandleOverrideClassScriptAuraProc(pTarget
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
,i
->cooldown
);
10217 // nothing do, just charges counter
10223 // Update charge (aura can be removed by triggers)
10224 if(casted
&& triggeredByAuraWithCharges
)
10226 // need found aura (can be dropped by triggers)
10227 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10228 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10229 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10231 if(itr
->second
== i
->triggeredByAura
)
10233 if(i
->triggeredByAura
->m_procCharges
> 0)
10234 i
->triggeredByAura
->m_procCharges
-= 1;
10236 i
->triggeredByAura
->UpdateAuraCharges();
10243 // Safely remove auras with zero charges
10244 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10247 if((*i
)->m_procCharges
== 0)
10249 RemoveAurasDueToSpell((*i
)->GetId());
10250 next
= auras
.begin();
10256 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10258 return SPELL_SCHOOL_MASK_NORMAL
;
10261 Player
* Unit::GetSpellModOwner()
10263 if(GetTypeId()==TYPEID_PLAYER
)
10264 return (Player
*)this;
10265 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10267 Unit
* owner
= GetOwner();
10268 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10269 return (Player
*)owner
;
10274 ///----------Pet responses methods-----------------
10275 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10277 Unit
*owner
= GetCharmerOrOwner();
10278 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10281 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10282 data
<< uint32(spellid
);
10283 data
<< uint8(msg
);
10284 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10287 void Unit::SendPetActionFeedback (uint8 msg
)
10289 Unit
* owner
= GetOwner();
10290 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10293 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10294 data
<< uint8(msg
);
10295 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10298 void Unit::SendPetTalk (uint32 pettalk
)
10300 Unit
* owner
= GetOwner();
10301 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10304 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10305 data
<< uint64(GetGUID());
10306 data
<< uint32(pettalk
);
10307 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10310 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10312 Unit
* owner
= GetOwner();
10313 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10316 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10317 data
<< uint64(GetGUID());
10318 data
<< uint8(0x0); // flags (0x1, 0x2)
10319 data
<< uint32(spellid
);
10320 data
<< uint32(cooltime
);
10322 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10325 void Unit::SendPetClearCooldown (uint32 spellid
)
10327 Unit
* owner
= GetOwner();
10328 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10331 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10332 data
<< uint32(spellid
);
10333 data
<< uint64(GetGUID());
10334 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10337 void Unit::SendPetAIReaction(uint64 guid
)
10339 Unit
* owner
= GetOwner();
10340 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10343 WorldPacket
data(SMSG_AI_REACTION
, 12);
10344 data
<< uint64(guid
) << uint32(00000002);
10345 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10348 ///----------End of Pet responses methods----------
10350 void Unit::StopMoving()
10352 clearUnitState(UNIT_STAT_MOVING
);
10354 // send explicit stop packet
10355 // rely on vmaps here because for example stormwind is in air
10356 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10357 //if (fabs(GetPositionZ() - z) < 2.0f)
10358 // Relocate(GetPositionX(), GetPositionY(), z);
10359 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10361 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10363 // update position and orientation;
10365 BuildHeartBeatMsg(&data
);
10366 SendMessageToSet(&data
,false);
10369 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10373 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10376 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10378 GetMotionMaster()->MovementExpired(false);
10379 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10381 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10383 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10387 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10389 GetMotionMaster()->MovementExpired(false);
10391 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10393 // restore appropriate movement generator
10395 GetMotionMaster()->MoveChase(getVictim());
10397 GetMotionMaster()->Initialize();
10399 // attack caster if can
10400 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10401 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10402 ((Creature
*)this)->AI()->AttackStart(caster
);
10406 if (GetTypeId() == TYPEID_PLAYER
)
10407 ((Player
*)this)->SetClientControl(this, !apply
);
10410 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10414 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10416 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10418 GetMotionMaster()->MoveConfused();
10422 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10424 GetMotionMaster()->MovementExpired(false);
10426 if (GetTypeId() == TYPEID_UNIT
)
10428 // if in combat restore movement generator
10430 GetMotionMaster()->MoveChase(getVictim());
10434 if(GetTypeId() == TYPEID_PLAYER
)
10435 ((Player
*)this)->SetClientControl(this, !apply
);
10438 bool Unit::IsSitState() const
10440 uint8 s
= getStandState();
10441 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10442 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10443 s
== PLAYER_STATE_SIT
;
10446 bool Unit::IsStandState() const
10448 uint8 s
= getStandState();
10449 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10452 void Unit::SetStandState(uint8 state
)
10454 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10456 if (IsStandState())
10457 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10459 if(GetTypeId()==TYPEID_PLAYER
)
10461 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10462 data
<< (uint8
)state
;
10463 ((Player
*)this)->GetSession()->SendPacket(&data
);
10467 bool Unit::IsPolymorphed() const
10469 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10472 void Unit::SetDisplayId(uint32 modelId
)
10474 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10476 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10478 Pet
*pet
= ((Pet
*)this);
10479 if(!pet
->isControlled())
10481 Unit
*owner
= GetOwner();
10482 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10483 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10487 void Unit::ClearComboPointHolders()
10489 while(!m_ComboPointHolders
.empty())
10491 uint32 lowguid
= *m_ComboPointHolders
.begin();
10493 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10494 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10495 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10497 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10501 void Unit::ClearAllReactives()
10504 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10505 m_reactiveTimer
[i
] = 0;
10507 if (HasAuraState( AURA_STATE_DEFENSE
))
10508 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10509 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10510 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10511 if (HasAuraState( AURA_STATE_CRIT
))
10512 ModifyAuraState(AURA_STATE_CRIT
, false);
10513 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10514 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10516 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10517 ((Player
*)this)->ClearComboPoints();
10520 void Unit::UpdateReactives( uint32 p_time
)
10522 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10524 ReactiveType reactive
= ReactiveType(i
);
10526 if(!m_reactiveTimer
[reactive
])
10529 if ( m_reactiveTimer
[reactive
] <= p_time
)
10531 m_reactiveTimer
[reactive
] = 0;
10533 switch ( reactive
)
10535 case REACTIVE_DEFENSE
:
10536 if (HasAuraState(AURA_STATE_DEFENSE
))
10537 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10539 case REACTIVE_HUNTER_PARRY
:
10540 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10541 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10543 case REACTIVE_CRIT
:
10544 if (HasAuraState(AURA_STATE_CRIT
))
10545 ModifyAuraState(AURA_STATE_CRIT
, false);
10547 case REACTIVE_HUNTER_CRIT
:
10548 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10549 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10551 case REACTIVE_OVERPOWER
:
10552 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10553 ((Player
*)this)->ClearComboPoints();
10561 m_reactiveTimer
[reactive
] -= p_time
;
10566 Unit
* Unit::SelectNearbyTarget() const
10568 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10570 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10571 cell
.SetNoCreate();
10573 std::list
<Unit
*> targets
;
10576 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10577 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10579 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10580 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10582 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10583 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10584 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10587 // remove current target
10589 targets
.remove(getVictim());
10591 // remove not LoS targets
10592 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10594 if(!IsWithinLOSInMap(*tIter
))
10596 std::list
<Unit
*>::iterator tIter2
= tIter
;
10598 targets
.erase(tIter2
);
10604 // no appropriate targets
10605 if(targets
.empty())
10609 uint32 rIdx
= urand(0,targets
.size()-1);
10610 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10611 for(uint32 i
= 0; i
< rIdx
; ++i
)
10617 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10621 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10622 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10626 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10627 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10631 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10634 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10636 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10639 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10641 if (CastingTime
> 7000) CastingTime
= 7000;
10642 if (CastingTime
< 1500) CastingTime
= 1500;
10644 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10645 CastingTime
= 3500;
10647 int32 overTime
= 0;
10649 bool DirectDamage
= false;
10650 bool AreaEffect
= false;
10652 for ( uint32 i
=0; i
<3;i
++)
10654 switch ( spellProto
->Effect
[i
] )
10656 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10657 case SPELL_EFFECT_POWER_DRAIN
:
10658 case SPELL_EFFECT_HEALTH_LEECH
:
10659 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10660 case SPELL_EFFECT_POWER_BURN
:
10661 case SPELL_EFFECT_HEAL
:
10662 DirectDamage
= true;
10664 case SPELL_EFFECT_APPLY_AURA
:
10665 switch ( spellProto
->EffectApplyAuraName
[i
] )
10667 case SPELL_AURA_PERIODIC_DAMAGE
:
10668 case SPELL_AURA_PERIODIC_HEAL
:
10669 case SPELL_AURA_PERIODIC_LEECH
:
10670 if ( GetSpellDuration(spellProto
) )
10671 overTime
= GetSpellDuration(spellProto
);
10674 // -5% per additional effect
10682 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10686 // Combined Spells with Both Over Time and Direct Damage
10687 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10689 // mainly for DoTs which are 3500 here otherwise
10690 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10691 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10692 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10693 // Portion to Over Time
10694 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10696 if ( damagetype
== DOT
)
10697 CastingTime
= uint32(CastingTime
* PtOT
);
10698 else if ( PtOT
< 1.0f
)
10699 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10704 // Area Effect Spells receive only half of bonus
10708 // -5% of total per any additional effect
10709 for ( uint8 i
=0; i
<effects
; ++i
)
10711 if ( CastingTime
> 175 )
10713 CastingTime
-= 175;
10722 return CastingTime
;
10725 void Unit::UpdateAuraForGroup(uint8 slot
)
10727 if(GetTypeId() == TYPEID_PLAYER
)
10729 Player
* player
= (Player
*)this;
10730 if(player
->GetGroup())
10732 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10733 player
->SetAuraUpdateMask(slot
);
10736 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10738 Pet
*pet
= ((Pet
*)this);
10739 if(pet
->isControlled())
10741 Unit
*owner
= GetOwner();
10742 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10744 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10745 pet
->SetAuraUpdateMask(slot
);
10751 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10753 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10754 return float(GetAttackTime(attType
))/1000.0f
;
10756 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10758 return 2.4; // fist attack
10760 switch (Weapon
->GetProto()->InventoryType
)
10762 case INVTYPE_2HWEAPON
:
10764 case INVTYPE_RANGED
:
10765 case INVTYPE_RANGEDRIGHT
:
10766 case INVTYPE_THROWN
:
10768 case INVTYPE_WEAPON
:
10769 case INVTYPE_WEAPONMAINHAND
:
10770 case INVTYPE_WEAPONOFFHAND
:
10772 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10776 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10778 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10779 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10780 if ((*itr
)->GetId() == spell_id
)
10786 bool Unit::IsUnderLastManaUseEffect() const
10788 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10791 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10793 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10795 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10798 player
->SetContestedPvPTimer(30000);
10799 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10801 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10802 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10803 // call MoveInLineOfSight for nearby contested guards
10804 SetVisibility(GetVisibility());
10806 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10808 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10809 // call MoveInLineOfSight for nearby contested guards
10810 SetVisibility(GetVisibility());
10814 void Unit::AddPetAura(PetAura
const* petSpell
)
10816 m_petAuras
.insert(petSpell
);
10817 if(Pet
* pet
= GetPet())
10818 pet
->CastPetAura(petSpell
);
10821 void Unit::RemovePetAura(PetAura
const* petSpell
)
10823 m_petAuras
.erase(petSpell
);
10824 if(Pet
* pet
= GetPet())
10825 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10828 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10830 Pet
* pet
= new Pet(HUNTER_PET
);
10832 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10838 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, GetGUID());
10839 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, GetGUID());
10840 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,getFaction());
10841 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10843 if(!pet
->InitStatsForLevel(creatureTarget
->getLevel()))
10845 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10850 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10851 // this enables pet details window (Shift+P)
10852 pet
->AIM_Initialize();
10853 pet
->InitPetCreateSpells();
10854 pet
->SetHealth(pet
->GetMaxHealth());