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
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4552 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4554 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4555 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4557 uint32 triggered_spell_id
= 0;
4558 Unit
* target
= pVictim
;
4559 int32 basepoints0
= 0;
4561 switch(hasteSpell
->SpellFamilyName
)
4563 case SPELLFAMILY_ROGUE
:
4565 switch(hasteSpell
->Id
)
4571 target
= SelectNearbyTarget();
4574 basepoints0
= damage
;
4575 triggered_spell_id
= 22482;
4583 // processed charge only counting case
4584 if(!triggered_spell_id
)
4587 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4591 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4596 if(!target
|| target
!=this && !target
->isAlive())
4599 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4603 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4605 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4607 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4608 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4613 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4615 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4616 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4618 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4619 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4621 uint32 triggered_spell_id
= 0;
4622 Unit
* target
= pVictim
;
4623 int32 basepoints0
= 0;
4625 switch(dummySpell
->SpellFamilyName
)
4627 case SPELLFAMILY_GENERIC
:
4629 switch (dummySpell
->Id
)
4635 // prevent damage back from weapon special attacks
4636 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4639 // return damage % to attacker but < 50% own total health
4640 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4641 if(basepoints0
> GetMaxHealth()/2)
4642 basepoints0
= GetMaxHealth()/2;
4644 triggered_spell_id
= 25997;
4652 // prevent chain of triggered spell from same triggered spell
4653 if(procSpell
&& procSpell
->Id
==26654)
4656 target
= SelectNearbyTarget();
4660 triggered_spell_id
= 26654;
4666 if (!procSpell
|| procSpell
->Id
== 24659)
4668 // Need remove one 24659 aura
4669 RemoveSingleAuraFromStack(24659, 0);
4670 RemoveSingleAuraFromStack(24659, 1);
4673 // Restless Strength
4676 // Need remove one 24662 aura
4677 RemoveSingleAuraFromStack(24662, 0);
4680 // Adaptive Warding (Frostfire Regalia set)
4688 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4689 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4691 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4693 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4703 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4705 case SPELL_SCHOOL_NORMAL
:
4706 case SPELL_SCHOOL_HOLY
:
4707 return false; // ignored
4708 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4709 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4710 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4711 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4712 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4720 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4728 for(int j
= 0; j
< 3; ++j
)
4730 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4739 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4741 case SPELL_SCHOOL_NORMAL
:
4742 return false; // ignore
4743 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4744 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4745 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4746 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4747 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4748 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4756 // Mana Leech (Passive) (Priest Pet Aura)
4760 target
= GetOwner();
4764 basepoints0
= int32(damage
* 2.5f
); // manaregen
4765 triggered_spell_id
= 34650;
4771 // Cast finish spell at last charge
4772 if (triggeredByAura
->m_procCharges
> 1)
4776 triggered_spell_id
= 33494;
4779 // Twisted Reflection (boss spell)
4781 triggered_spell_id
= 21064;
4783 // Vampiric Aura (boss spell)
4786 basepoints0
= 3 * damage
; // 300%
4787 if (basepoints0
< 0)
4790 triggered_spell_id
= 31285;
4794 // Aura of Madness (Darkmoon Card: Madness trinket)
4795 //=====================================================
4796 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4797 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4798 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4799 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4800 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4801 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4802 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4803 // 41011 Martyr Complex: +35 stamina (All classes)
4804 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4805 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4808 if(GetTypeId() != TYPEID_PLAYER
)
4811 // Select class defined buff
4814 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4815 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4817 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4818 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4821 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4822 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4824 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4825 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4828 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4829 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4830 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4831 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4833 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4834 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4837 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4839 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4840 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4848 if (roll_chance_i(10))
4849 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4853 // TODO: need find item for aura and triggered spells
4854 // Sunwell Exalted Caster Neck (??? neck)
4855 // cast ??? Light's Wrath if Exalted by Aldor
4856 // cast ??? Arcane Bolt if Exalted by Scryers*/
4858 return false; // disable for while
4861 if(GetTypeId() != TYPEID_PLAYER)
4864 // Get Aldor reputation rank
4865 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4868 triggered_spell_id = ???
4871 // Get Scryers reputation rank
4872 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4874 triggered_spell_id = ???
4879 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4880 // cast 45479 Light's Wrath if Exalted by Aldor
4881 // cast 45429 Arcane Bolt if Exalted by Scryers
4884 if(GetTypeId() != TYPEID_PLAYER
)
4887 // Get Aldor reputation rank
4888 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4891 triggered_spell_id
= 45479;
4894 // Get Scryers reputation rank
4895 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4897 triggered_spell_id
= 45429;
4902 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4903 // cast 45480 Light's Strength if Exalted by Aldor
4904 // cast 45428 Arcane Strike if Exalted by Scryers
4907 if(GetTypeId() != TYPEID_PLAYER
)
4910 // Get Aldor reputation rank
4911 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4914 triggered_spell_id
= 45480;
4917 // Get Scryers reputation rank
4918 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4920 triggered_spell_id
= 45428;
4925 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4926 // cast 45431 Arcane Insight if Exalted by Aldor
4927 // cast 45432 Light's Ward if Exalted by Scryers
4930 if(GetTypeId() != TYPEID_PLAYER
)
4933 // Get Aldor reputation rank
4934 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4937 triggered_spell_id
= 45432;
4940 // Get Scryers reputation rank
4941 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4944 triggered_spell_id
= 45431;
4949 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
4950 // cast 45478 Light's Salvation if Exalted by Aldor
4951 // cast 45430 Arcane Surge if Exalted by Scryers
4954 if(GetTypeId() != TYPEID_PLAYER
)
4957 // Get Aldor reputation rank
4958 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4961 triggered_spell_id
= 45478;
4964 // Get Scryers reputation rank
4965 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4967 triggered_spell_id
= 45430;
4975 case SPELLFAMILY_MAGE
:
4978 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
4980 if (getPowerType() != POWER_MANA
)
4984 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
4986 triggered_spell_id
= 29442;
4989 // Master of Elements
4990 if (dummySpell
->SpellIconID
== 1920)
4996 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
4997 if( basepoints0
<=0 )
5001 triggered_spell_id
= 29077;
5004 switch(dummySpell
->Id
)
5013 switch (dummySpell
->Id
)
5015 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5016 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5017 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5018 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5019 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5021 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5025 triggered_spell_id
= 12654;
5031 //last charge and crit
5032 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5034 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5035 return true; // charge counting (will removed)
5038 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5039 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5044 case SPELLFAMILY_WARRIOR
:
5047 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5049 // check attack comes not from behind
5050 if (!HasInArc(M_PI
, pVictim
))
5053 triggered_spell_id
= 22858;
5058 case SPELLFAMILY_WARLOCK
:
5060 // Seed of Corruption
5061 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5063 Modifier
* mod
= triggeredByAura
->GetModifier();
5064 // if damage is more than need or target die from damage deal finish spell
5065 // FIX ME: not triggered currently at death
5066 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5068 // remember guid before aura delete
5069 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5071 // Remove aura (before cast for prevent infinite loop handlers)
5072 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5074 // Cast finish spell (triggeredByAura already not exist!)
5075 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5076 return true; // no hidden cooldown
5080 mod
->m_amount
-=damage
;
5083 // Seed of Corruption (Mobs cast) - no die req
5084 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5086 Modifier
* mod
= triggeredByAura
->GetModifier();
5087 // if damage is more than need deal finish spell
5088 if( mod
->m_amount
<= damage
)
5090 // remember guid before aura delete
5091 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5093 // Remove aura (before cast for prevent infinite loop handlers)
5094 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5096 // Cast finish spell (triggeredByAura already not exist!)
5097 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5098 return true; // no hidden cooldown
5101 mod
->m_amount
-=damage
;
5104 switch(dummySpell
->Id
)
5111 triggered_spell_id
= 17941;
5120 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5122 triggered_spell_id
= 30294;
5125 // Shadowflame (Voidheart Raiment set bonus)
5128 triggered_spell_id
= 37379;
5131 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5139 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5140 triggered_spell_id
= 37382;
5143 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5146 triggered_spell_id
= 37378;
5152 case SPELLFAMILY_PRIEST
:
5155 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5157 if(!pVictim
|| !pVictim
->isAlive())
5160 // pVictim is caster of aura
5161 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5165 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5166 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5167 return true; // no hidden cooldown
5169 switch(dummySpell
->Id
)
5174 if(!pVictim
|| !pVictim
->isAlive())
5177 // pVictim is caster of aura
5178 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5182 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5183 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5184 return true; // no hidden cooldown
5186 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5189 // Shadow Word: Pain
5190 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5191 triggered_spell_id
= 40441;
5193 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5194 triggered_spell_id
= 40440;
5201 // Oracle Healing Bonus ("Garments of the Oracle" set)
5205 basepoints0
= int32(damage
* 10/100);
5207 triggered_spell_id
= 26170;
5210 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5213 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5217 basepoints0
= int32(damage
* 2 / 100);
5219 triggered_spell_id
= 39373;
5222 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5225 triggered_spell_id
= 28810;
5231 case SPELLFAMILY_DRUID
:
5233 switch(dummySpell
->Id
)
5235 // Healing Touch (Dreamwalker Raiment set)
5239 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5241 triggered_spell_id
= 28742;
5244 // Healing Touch Refund (Idol of Longevity trinket)
5248 triggered_spell_id
= 28848;
5251 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5256 triggered_spell_id
= 37238;
5259 // Druid Tier 6 Trinket
5265 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5267 triggered_spell_id
= 40445;
5271 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5273 triggered_spell_id
= 40446;
5276 // Mangle (cat/bear)
5277 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5279 triggered_spell_id
= 40452;
5285 if (!roll_chance_f(chance
))
5294 // Deadly Interrupt Effect
5295 triggered_spell_id
= 32747;
5301 case SPELLFAMILY_ROGUE
:
5303 switch(dummySpell
->Id
)
5305 // Deadly Throw Interrupt
5308 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5312 triggered_spell_id
= 32747;
5317 if( dummySpell
->SpellIconID
== 2116 )
5322 // only rogue's finishing moves (maybe need additional checks)
5323 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5324 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5328 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5329 if(basepoints0
<= 0)
5333 triggered_spell_id
= 31663;
5338 case SPELLFAMILY_HUNTER
:
5340 // Thrill of the Hunt
5341 if ( dummySpell
->SpellIconID
== 2236 )
5347 basepoints0
= procSpell
->manaCost
* 40/100;
5348 if(basepoints0
<= 0)
5352 triggered_spell_id
= 34720;
5357 case SPELLFAMILY_PALADIN
:
5359 // Seal of Righteousness - melee proc dummy
5360 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5362 if(GetTypeId() != TYPEID_PLAYER
)
5366 switch (triggeredByAura
->GetId())
5368 case 21084: spellId
= 25742; break; // Rank 1
5369 case 20287: spellId
= 25740; break; // Rank 2
5370 case 20288: spellId
= 25739; break; // Rank 3
5371 case 20289: spellId
= 25738; break; // Rank 4
5372 case 20290: spellId
= 25737; break; // Rank 5
5373 case 20291: spellId
= 25736; break; // Rank 6
5374 case 20292: spellId
= 25735; break; // Rank 7
5375 case 20293: spellId
= 25713; break; // Rank 8
5376 case 27155: spellId
= 27156; break; // Rank 9
5378 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5381 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5382 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5384 float damageBasePoints
;
5385 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5387 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5389 // one hand weapon/no weapon
5390 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5392 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5394 // apply damage bonuses manually
5395 if(damagePoint
>= 0)
5396 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5398 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5399 return true; // no hidden cooldown
5401 // Seal of Blood do damage trigger
5402 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5404 switch(triggeredByAura
->GetEffIndex())
5407 // prevent chain triggering
5408 if(procSpell
&& procSpell
->Id
==31893 )
5411 triggered_spell_id
= 31893;
5416 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5418 triggered_spell_id
= 32221;
5424 switch(dummySpell
->Id
)
5426 // Holy Power (Redemption Armor set)
5432 // Set class defined buff
5433 switch (pVictim
->getClass())
5439 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5443 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5447 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5450 triggered_spell_id
= 28790; // Increases the friendly target's armor
5460 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5463 triggered_spell_id
= 31803;
5470 // if healed by another unit (pVictim)
5475 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5477 triggered_spell_id
= 31786;
5480 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5488 // Flash of light/Holy light
5489 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5491 triggered_spell_id
= 40471;
5495 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5497 triggered_spell_id
= 40472;
5503 if (!roll_chance_f(chance
))
5511 case SPELLFAMILY_SHAMAN
:
5513 switch(dummySpell
->Id
)
5515 // Totemic Power (The Earthshatterer set)
5521 // Set class defined buff
5522 switch (pVictim
->getClass())
5528 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5532 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5536 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5539 triggered_spell_id
= 28827; // Increases the friendly target's armor
5546 // Lesser Healing Wave (Totem of Flowing Water Relic)
5550 triggered_spell_id
= 28850;
5553 // Windfury Weapon (Passive) 1-5 Ranks
5556 if(GetTypeId()!=TYPEID_PLAYER
)
5559 if(!castItem
|| !castItem
->IsEquipped())
5562 // custom cooldown processing case
5563 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5567 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5569 case 283: spellId
= 33757; break; //1 Rank
5570 case 284: spellId
= 33756; break; //2 Rank
5571 case 525: spellId
= 33755; break; //3 Rank
5572 case 1669:spellId
= 33754; break; //4 Rank
5573 case 2636:spellId
= 33727; break; //5 Rank
5576 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5577 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5582 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5583 if(!windfurySpellEntry
)
5585 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5589 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5592 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5594 // Value gained from additional AP
5595 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5596 triggered_spell_id
= 33750;
5601 // Value gained from additional AP
5602 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5603 triggered_spell_id
= 25504;
5606 // apply cooldown before cast to prevent processing itself
5608 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5611 for ( uint32 i
= 0; i
<2; ++i
)
5612 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5616 // Shaman Tier 6 Trinket
5623 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5625 triggered_spell_id
= 40465; // Lightning Bolt
5628 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5630 triggered_spell_id
= 40465; // Lesser Healing Wave
5633 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5635 triggered_spell_id
= 40466; // Stormstrike
5641 if (!roll_chance_f(chance
))
5650 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5652 if(GetTypeId() != TYPEID_PLAYER
)
5656 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5658 triggered_spell_id
= 379;
5661 // Lightning Overload
5662 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5664 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5667 // custom cooldown processing case
5668 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5672 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5673 switch (procSpell
->Id
)
5676 case 403: spellId
= 45284; break; // Rank 1
5677 case 529: spellId
= 45286; break; // Rank 2
5678 case 548: spellId
= 45287; break; // Rank 3
5679 case 915: spellId
= 45288; break; // Rank 4
5680 case 943: spellId
= 45289; break; // Rank 5
5681 case 6041: spellId
= 45290; break; // Rank 6
5682 case 10391: spellId
= 45291; break; // Rank 7
5683 case 10392: spellId
= 45292; break; // Rank 8
5684 case 15207: spellId
= 45293; break; // Rank 9
5685 case 15208: spellId
= 45294; break; // Rank 10
5686 case 25448: spellId
= 45295; break; // Rank 11
5687 case 25449: spellId
= 45296; break; // Rank 12
5689 case 421: spellId
= 45297; break; // Rank 1
5690 case 930: spellId
= 45298; break; // Rank 2
5691 case 2860: spellId
= 45299; break; // Rank 3
5692 case 10605: spellId
= 45300; break; // Rank 4
5693 case 25439: spellId
= 45301; break; // Rank 5
5694 case 25442: spellId
= 45302; break; // Rank 6
5696 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5699 // No thread generated mod
5700 SpellModifier
*mod
= new SpellModifier
;
5701 mod
->op
= SPELLMOD_THREAT
;
5703 mod
->type
= SPELLMOD_PCT
;
5704 mod
->spellId
= dummySpell
->Id
;
5706 mod
->lastAffected
= NULL
;
5707 mod
->mask
= 0x0000000000000003LL
;
5709 ((Player
*)this)->AddSpellMod(mod
, true);
5711 // Remove cooldown (Chain Lightning - have Category Recovery time)
5712 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5713 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5715 // Hmmm.. in most case spells already set half basepoints but...
5716 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5718 // 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.
5719 // So - no add changes :)
5720 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5722 ((Player
*)this)->AddSpellMod(mod
, false);
5724 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5725 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5735 // processed charge only counting case
5736 if(!triggered_spell_id
)
5739 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5743 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5748 if(!target
|| target
!=this && !target
->isAlive())
5751 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5755 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5757 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5759 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5760 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5765 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5767 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5769 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5770 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5772 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5773 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5774 int32 basepoints0
= 0;
5776 switch(auraSpellInfo
->SpellFamilyName
)
5778 case SPELLFAMILY_GENERIC
:
5780 switch(auraSpellInfo
->Id
)
5782 // Aegis of Preservation
5784 //Aegis Heal (instead non-existed triggered spell)
5785 triggered_spell_id
= 23781;
5788 // Elune's Touch (moonkin mana restore)
5791 // Elune's Touch (instead non-existed triggered spell)
5792 triggered_spell_id
= 33926;
5793 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5800 // only for cast with mana price
5801 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5803 break; // fall through to normal cast
5808 // at melee hit call std triggered spell
5809 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5810 break; // fall through to normal cast
5812 // Mark of Conquest - else (at range hit) called custom case
5813 triggered_spell_id
= 39557;
5819 return true; // nothing to do
5820 // Forgotten Knowledge (Blade of Wizardry)
5822 // only for harmful enemy targeted spell
5823 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5825 break; // fall through to normal cast
5826 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5829 // proc only at non-crit hits
5830 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5832 break; // fall through to normal cast
5834 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5840 //only periodic damage can trigger spell
5842 for(int j
= 0; j
< 3; ++j
)
5844 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5845 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5846 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5855 break; // fall through to normal cast
5857 // Evasive Maneuvers (Commendation of Kael'thas)
5860 // damage taken that reduces below 35% health
5861 // does NOT mean you must have been >= 35% before
5862 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5864 break; // fall through to normal cast
5868 switch(triggered_spell_id
)
5873 // applied only for main target
5874 if(!pVictim
|| pVictim
!= getVictim())
5877 // continue normal case
5880 // Shamanistic Rage triggered spell
5882 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5887 case SPELLFAMILY_MAGE
:
5889 switch(auraSpellInfo
->SpellIconID
)
5893 //Blazing Speed (instead non-existed triggered spell)
5894 triggered_spell_id
= 31643;
5898 switch(auraSpellInfo
->Id
)
5900 // Persistent Shield (Scarab Brooch)
5902 basepoints0
= int32(damage
* 0.15f
);
5907 case SPELLFAMILY_WARRIOR
:
5910 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5912 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5913 //and effect[1]==TriggerSpell
5914 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5916 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5919 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5920 break; // fall through to normal cast
5924 case SPELLFAMILY_WARLOCK
:
5927 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5929 // last case for Hellfire that damage caster also but don't must stun caster
5930 if( pVictim
== this )
5935 switch (triggeredByAura
->GetId())
5937 case 18096: chance
= 13.0f
; break;
5938 case 18073: chance
= 26.0f
; break;
5940 if (!roll_chance_f(chance
))
5943 // Pyroclasm (instead non-existed triggered spell)
5944 triggered_spell_id
= 18093;
5949 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
5952 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
5953 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
5955 //Improved Drain Soul
5956 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
5958 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
5959 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
5962 triggered_spell_id
= 18371;
5970 break; // fall through to normal cast
5974 case SPELLFAMILY_PRIEST
:
5977 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
5979 switch (triggeredByAura
->GetSpellProto()->Id
)
5981 case 27811: triggered_spell_id
= 27813; break;
5982 case 27815: triggered_spell_id
= 27817; break;
5983 case 27816: triggered_spell_id
= 27818; break;
5985 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
5989 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
5990 basepoints0
= heal_amount
/3;
5995 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
==7958)
5997 switch(triggeredByAura
->GetSpellProto()->Id
)
6000 triggered_spell_id
= 28377; break; // Rank 1
6002 triggered_spell_id
= 28378; break; // Rank 2
6004 triggered_spell_id
= 28379; break; // Rank 3
6006 triggered_spell_id
= 28380; break; // Rank 4
6008 triggered_spell_id
= 28381; break; // Rank 5
6010 triggered_spell_id
= 28382; break; // Rank 6
6012 triggered_spell_id
= 28385; break; // Rank 7
6014 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6022 case SPELLFAMILY_DRUID
:
6024 switch(auraSpellInfo
->Id
)
6026 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6029 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6031 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6032 triggered_spell_id
= 34299;
6035 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6042 triggered_spell_id
=37340; break;// Ursine Blessing
6044 triggered_spell_id
=37341; break;// Feline Blessing
6046 triggered_spell_id
=37342; break;// Slyvan Blessing
6048 triggered_spell_id
=37343; break;// Lunar Blessing
6050 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6061 case SPELLFAMILY_ROGUE
:
6063 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6065 switch(auraSpellInfo
->SpellIconID
)
6070 // skip non offhand attacks
6071 if(attackType
!=OFF_ATTACK
)
6073 break; // fall through to normal cast
6079 case SPELLFAMILY_PALADIN
:
6081 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6083 switch(auraSpellInfo
->Id
)
6085 // Lightning Capacitor
6088 // trinket ProcTriggerSpell but for safe checks for player
6089 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6092 if(((Player
*)this)->HasSpellCooldown(37657))
6096 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6097 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6098 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6102 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6103 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6104 if((*itr
)->GetId()==37658)
6107 // release at 3 aura in stack
6109 return true; // main triggered spell casted anyway
6111 RemoveAurasDueToSpell(37658);
6112 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6117 // Healing Trance (instead non-existed triggered spell)
6118 triggered_spell_id
= 37706;
6121 // HoTs on Heals (Fel Reaver's Piston trinket)
6124 // at direct heal effect
6125 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6128 // single proc at time
6129 AuraList
const& scAuras
= GetSingleCastAuras();
6130 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6131 if((*itr
)->GetId()==triggered_spell_id
)
6134 // positive cast at victim instead self
6139 switch(auraSpellInfo
->SpellIconID
)
6143 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6151 // procspell is triggered spell but we need mana cost of original casted spell
6152 uint32 originalSpellId
= procSpell
->Id
;
6155 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6157 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6159 switch(procSpell
->Id
)
6161 case 25914: originalSpellId
= 20473; break;
6162 case 25913: originalSpellId
= 20929; break;
6163 case 25903: originalSpellId
= 20930; break;
6164 case 27175: originalSpellId
= 27174; break;
6165 case 33074: originalSpellId
= 33072; break;
6167 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6173 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6176 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6180 // percent stored in effect 1 (class scripts) base points
6181 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6183 basepoints0
= originalSpell
->manaCost
*percent
/100;
6184 triggered_spell_id
= 20272;
6193 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6195 switch(auraSpellInfo
->SpellIconID
)
6197 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6200 if(!pVictim
|| !pVictim
->isAlive())
6203 switch(triggeredByAura
->GetSpellProto()->Id
)
6206 triggered_spell_id
= 20268; // Rank 1
6209 triggered_spell_id
= 20352; // Rank 2
6212 triggered_spell_id
= 20353; // Rank 3
6215 triggered_spell_id
= 27165; // Rank 4
6218 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6222 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6223 return true; // no hidden cooldown
6225 //Judgement of Light
6228 if(!pVictim
|| !pVictim
->isAlive())
6231 // overwrite non existing triggered spell call in spell.dbc
6232 switch(triggeredByAura
->GetSpellProto()->Id
)
6235 triggered_spell_id
= 20267; // Rank 1
6238 triggered_spell_id
= 20341; // Rank 2
6241 triggered_spell_id
= 20342; // Rank 3
6244 triggered_spell_id
= 20343; // Rank 4
6247 triggered_spell_id
= 27163; // Rank 5
6250 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6253 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6254 return true; // no hidden cooldown
6258 // custom check for proc spell
6259 switch(auraSpellInfo
->Id
)
6261 // Bonus Healing (item spell)
6264 if(!pVictim
|| !pVictim
->isAlive())
6267 // bonus if health < 50%
6268 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6271 // cast at target positive spell
6276 switch(triggered_spell_id
)
6280 // prevent chain of triggered spell from same triggered spell
6281 if(procSpell
&& procSpell
->Id
==20424)
6287 case SPELLFAMILY_SHAMAN
:
6289 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6291 switch(auraSpellInfo
->SpellIconID
)
6295 switch(auraSpellInfo
->Id
)
6297 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6299 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6300 triggered_spell_id
= 23552;
6304 case 23552: // Lightning Shield - trigger shield damage
6306 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6307 triggered_spell_id
= 27635;
6314 // Mana Surge (Shaman T1 bonus)
6320 basepoints0
= procSpell
->manaCost
* 35/100;
6321 triggered_spell_id
= 23571;
6328 if(GetTypeId()!=TYPEID_PLAYER
)
6331 // damage taken that reduces below 30% health
6332 // does NOT mean you must have been >= 30% before
6333 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6336 triggered_spell_id
= 31616;
6338 // need check cooldown now
6339 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6342 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6344 if(pVictim
&& pVictim
->isAlive())
6345 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6351 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6352 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
==7358)
6359 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
==37)
6361 // overwrite non existing triggered spell call in spell.dbc
6362 switch(triggeredByAura
->GetSpellProto()->Id
)
6365 triggered_spell_id
= 26364; break; // Rank 1
6367 triggered_spell_id
= 26365; break; // Rank 2
6369 triggered_spell_id
= 26366; break; // Rank 3
6371 triggered_spell_id
= 26367; break; // Rank 4
6373 triggered_spell_id
= 26369; break; // Rank 5
6375 triggered_spell_id
= 26370; break; // Rank 6
6377 triggered_spell_id
= 26363; break; // Rank 7
6379 triggered_spell_id
= 26371; break; // Rank 8
6381 triggered_spell_id
= 26372; break; // Rank 9
6383 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6394 // standard non-dummy case
6395 if(!triggered_spell_id
)
6397 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6401 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6405 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6409 // not allow proc extra attack spell at extra attack
6410 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6413 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6417 if(!target
|| target
!=this && !target
->isAlive())
6421 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6423 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6425 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6426 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6431 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6433 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6435 if(!pVictim
|| !pVictim
->isAlive())
6438 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6439 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6441 uint32 triggered_spell_id
= 0;
6445 case 836: // Improved Blizzard (Rank 1)
6447 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6449 triggered_spell_id
= 12484;
6452 case 988: // Improved Blizzard (Rank 2)
6454 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6456 triggered_spell_id
= 12485;
6459 case 989: // Improved Blizzard (Rank 3)
6461 if (!procSpell
|| procSpell
->SpellVisual
!=9487)
6463 triggered_spell_id
= 12486;
6466 case 4086: // Improved Mend Pet (Rank 1)
6467 case 4087: // Improved Mend Pet (Rank 2)
6469 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6470 if(!roll_chance_i(chance
))
6473 triggered_spell_id
= 24406;
6476 case 4533: // Dreamwalker Raiment 2 pieces bonus
6479 if (!roll_chance_i(50))
6482 switch (pVictim
->getPowerType())
6484 case POWER_MANA
: triggered_spell_id
= 28722; break;
6485 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6486 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6492 case 4537: // Dreamwalker Raiment 6 pieces bonus
6493 triggered_spell_id
= 28750; // Blessing of the Claw
6495 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6496 triggered_spell_id
= 37445; // Mana Surge
6501 if(!triggered_spell_id
)
6504 // standard non-dummy case
6505 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6509 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6513 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6516 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6518 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6519 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6524 void Unit::setPowerType(Powers new_powertype
)
6526 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6528 if(GetTypeId() == TYPEID_PLAYER
)
6530 if(((Player
*)this)->GetGroup())
6531 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6533 else if(((Creature
*)this)->isPet())
6535 Pet
*pet
= ((Pet
*)this);
6536 if(pet
->isControlled())
6538 Unit
*owner
= GetOwner();
6539 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6540 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6544 switch(new_powertype
)
6550 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6551 SetPower( POWER_RAGE
,0);
6554 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6555 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6558 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6559 SetPower( POWER_ENERGY
,0);
6561 case POWER_HAPPINESS
:
6562 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6563 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6568 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6570 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6573 static uint64 guid
= 0; // prevent repeating spam same faction problem
6575 if(GetGUID() != guid
)
6577 if(GetTypeId() == TYPEID_PLAYER
)
6578 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6580 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6587 bool Unit::IsHostileTo(Unit
const* unit
) const
6589 // always non-hostile to self
6593 // always non-hostile to GM in GM mode
6594 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6597 // always hostile to enemy
6598 if(getVictim()==unit
|| unit
->getVictim()==this)
6601 // test pet/charm masters instead pers/charmeds
6602 Unit
const* testerOwner
= GetCharmerOrOwner();
6603 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6605 // always hostile to owner's enemy
6606 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6609 // always hostile to enemy owner
6610 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6613 // always hostile to owner of owner's enemy
6614 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6617 Unit
const* tester
= testerOwner
? testerOwner
: this;
6618 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6620 // always non-hostile to target with common owner, or to owner/pet
6624 // special cases (Duel, etc)
6625 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6627 Player
const* pTester
= (Player
const*)tester
;
6628 Player
const* pTarget
= (Player
const*)target
;
6631 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6635 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6639 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6643 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6647 // Green/Blue (can't attack)
6648 if(pTester
->GetTeam()==pTarget
->GetTeam())
6651 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6652 return pTester
->IsPvP() && pTarget
->IsPvP();
6655 // faction base cases
6656 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6657 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6658 if(!tester_faction
|| !target_faction
)
6661 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6664 // PvC forced reaction and reputation case
6665 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6668 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6669 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6670 return forceItr
->second
<= REP_HOSTILE
;
6672 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6673 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6674 if(raw_target_faction
->reputationListID
>=0)
6675 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6676 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6678 // CvP forced reaction and reputation case
6679 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6682 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6683 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6684 return forceItr
->second
<= REP_HOSTILE
;
6686 // apply reputation state
6687 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6688 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6689 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6692 // common faction based case (CvC,PvC,CvP)
6693 return tester_faction
->IsHostileTo(*target_faction
);
6696 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6698 // always friendly to self
6702 // always friendly to GM in GM mode
6703 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6706 // always non-friendly to enemy
6707 if(getVictim()==unit
|| unit
->getVictim()==this)
6710 // test pet/charm masters instead pers/charmeds
6711 Unit
const* testerOwner
= GetCharmerOrOwner();
6712 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6714 // always non-friendly to owner's enemy
6715 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6718 // always non-friendly to enemy owner
6719 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6722 // always non-friendly to owner of owner's enemy
6723 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6726 Unit
const* tester
= testerOwner
? testerOwner
: this;
6727 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6729 // always friendly to target with common owner, or to owner/pet
6733 // special cases (Duel)
6734 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6736 Player
const* pTester
= (Player
const*)tester
;
6737 Player
const* pTarget
= (Player
const*)target
;
6740 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6744 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6748 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6752 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6756 // Green/Blue (non-attackable)
6757 if(pTester
->GetTeam()==pTarget
->GetTeam())
6760 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6761 return !pTarget
->IsPvP();
6764 // faction base cases
6765 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6766 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6767 if(!tester_faction
|| !target_faction
)
6770 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6773 // PvC forced reaction and reputation case
6774 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6777 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6778 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6779 return forceItr
->second
>= REP_FRIENDLY
;
6781 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6782 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6783 if(raw_target_faction
->reputationListID
>=0)
6784 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6785 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6787 // CvP forced reaction and reputation case
6788 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6791 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6792 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6793 return forceItr
->second
>= REP_FRIENDLY
;
6795 // apply reputation state
6796 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6797 if(raw_tester_faction
->reputationListID
>=0 )
6798 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6801 // common faction based case (CvC,PvC,CvP)
6802 return tester_faction
->IsFriendlyTo(*target_faction
);
6805 bool Unit::IsHostileToPlayers() const
6807 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6811 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6812 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6815 return my_faction
->IsHostileToPlayers();
6818 bool Unit::IsNeutralToAll() const
6820 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6824 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6825 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6828 return my_faction
->IsNeutralToAll();
6831 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6833 if(!victim
|| victim
== this)
6836 // dead units can neither attack nor be attacked
6837 if(!isAlive() || !victim
->isAlive())
6840 // player cannot attack in mount state
6841 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6844 // nobody can attack GM in GM-mode
6845 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6847 if(((Player
*)victim
)->isGameMaster())
6852 if(((Creature
*)victim
)->IsInEvadeMode())
6856 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6857 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6858 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6862 if (m_attacking
== victim
)
6864 // switch to melee attack from ranged/magic
6865 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6867 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6868 SendAttackStart(victim
);
6877 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6880 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6881 m_attacking
= victim
;
6882 m_attacking
->_addAttacker(this);
6884 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6885 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6887 if(GetTypeId()==TYPEID_UNIT
)
6889 WorldPacket
data(SMSG_AI_REACTION
, 12);
6891 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6892 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6894 ((Creature
*)this)->CallAssistence();
6895 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6898 // delay offhand weapon attack to next attack time
6899 if(haveOffhandWeapon())
6900 resetAttackTimer(OFF_ATTACK
);
6903 SendAttackStart(victim
);
6908 bool Unit::AttackStop()
6913 Unit
* victim
= m_attacking
;
6915 m_attacking
->_removeAttacker(this);
6919 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6921 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6923 InterruptSpell(CURRENT_MELEE_SPELL
);
6925 if( GetTypeId()==TYPEID_UNIT
)
6927 // reset call assistance
6928 ((Creature
*)this)->SetNoCallAssistence(false);
6931 SendAttackStop(victim
);
6936 void Unit::CombatStop(bool cast
)
6938 if(cast
& IsNonMeleeSpellCasted(false))
6939 InterruptNonMeleeSpells(false);
6942 RemoveAllAttackers();
6943 if( GetTypeId()==TYPEID_PLAYER
)
6944 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6948 void Unit::CombatStopWithPets(bool cast
)
6951 if(Pet
* pet
= GetPet())
6952 pet
->CombatStop(cast
);
6953 if(Unit
* charm
= GetCharm())
6954 charm
->CombatStop(cast
);
6955 if(GetTypeId()==TYPEID_PLAYER
)
6957 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
6958 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
6959 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
6960 guardian
->CombatStop(cast
);
6964 bool Unit::isAttackingPlayer() const
6966 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
6969 Pet
* pet
= GetPet();
6970 if(pet
&& pet
->isAttackingPlayer())
6973 Unit
* charmed
= GetCharm();
6974 if(charmed
&& charmed
->isAttackingPlayer())
6977 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
6981 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
6982 if(totem
&& totem
->isAttackingPlayer())
6990 void Unit::RemoveAllAttackers()
6992 while (!m_attackers
.empty())
6994 AttackerSet::iterator iter
= m_attackers
.begin();
6995 if(!(*iter
)->AttackStop())
6997 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
6998 m_attackers
.erase(iter
);
7003 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7007 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7009 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7010 if(GetTypeId() == TYPEID_PLAYER
)
7012 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7013 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7015 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7016 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7017 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7018 if (spellInfo
->CasterAuraState
== flag
)
7019 CastSpell(this, itr
->first
, true, NULL
);
7026 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7028 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7029 Unit::AuraMap
& tAuras
= GetAuras();
7030 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7032 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7033 if (spellProto
->CasterAuraState
== flag
)
7035 // exceptions (applied at state but not removed at state change)
7037 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7052 Unit
*Unit::GetOwner() const
7054 uint64 ownerid
= GetOwnerGUID();
7057 return ObjectAccessor::GetUnit(*this, ownerid
);
7060 Unit
*Unit::GetCharmer() const
7062 if(uint64 charmerid
= GetCharmerGUID())
7063 return ObjectAccessor::GetUnit(*this, charmerid
);
7067 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7069 uint64 guid
= GetCharmerOrOwnerGUID();
7070 if(IS_PLAYER_GUID(guid
))
7071 return ObjectAccessor::GetPlayer(*this, guid
);
7073 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7076 Pet
* Unit::GetPet() const
7078 if(uint64 pet_guid
= GetPetGUID())
7080 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7083 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7084 const_cast<Unit
*>(this)->SetPet(0);
7090 Unit
* Unit::GetCharm() const
7092 if(uint64 charm_guid
= GetCharmGUID())
7094 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7097 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7098 const_cast<Unit
*>(this)->SetCharm(0);
7104 void Unit::SetPet(Pet
* pet
)
7106 SetUInt64Value(UNIT_FIELD_SUMMON
,pet
? pet
->GetGUID() : 0);
7108 // FIXME: hack, speed must be set only at follow
7110 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7111 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
7114 void Unit::SetCharm(Unit
* charmed
)
7116 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
7119 void Unit::UnsummonAllTotems()
7121 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7126 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7127 if (OldTotem
&& OldTotem
->isTotem())
7128 ((Totem
*)OldTotem
)->UnSummon();
7132 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7135 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7136 data
.append(pVictim
->GetPackGUID());
7137 data
.append(GetPackGUID());
7138 data
<< uint32(SpellID
);
7139 data
<< uint32(Damage
);
7140 data
<< uint8(critical
? 1 : 0);
7141 data
<< uint8(0); // unused in client?
7142 SendMessageToSet(&data
, true);
7145 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7147 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7148 data
.append(pVictim
->GetPackGUID());
7149 data
.append(GetPackGUID());
7150 data
<< uint32(SpellID
);
7151 data
<< uint32(powertype
);
7152 data
<< uint32(Damage
);
7153 //data << uint8(critical ? 1 : 0); // removed in 2.4.0
7154 SendMessageToSet(&data
, true);
7157 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7159 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7162 int32 BonusDamage
= 0;
7163 if( GetTypeId()==TYPEID_UNIT
)
7165 // Pets just add their bonus damage to their spell damage
7166 // note that their spell damage is just gain of their own auras
7167 if (((Creature
*)this)->isPet())
7169 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7171 // For totems get damage bonus from owner (statue isn't totem in fact)
7172 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7174 if(Unit
* owner
= GetOwner())
7175 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7180 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7182 // Taken/Done fixed damage bonus auras
7183 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7184 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7186 // Damage over Time spells bonus calculation
7187 float DotFactor
= 1.0f
;
7188 if(damagetype
== DOT
)
7190 int32 DotDuration
= GetSpellDuration(spellProto
);
7194 if(DotDuration
> 30000) DotDuration
= 30000;
7195 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7197 for(int j
= 0; j
< 3; j
++)
7199 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7200 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7201 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7208 if(spellProto
->EffectAmplitude
[x
] != 0)
7209 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7212 DoneAdvertisedBenefit
/= DotTicks
;
7213 TakenAdvertisedBenefit
/= DotTicks
;
7218 // Taken/Done total percent damage auras
7219 float DoneTotalMod
= 1.0f
;
7220 float TakenTotalMod
= 1.0f
;
7223 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7224 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7226 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7227 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7228 // -1 == any item class (not wand then)
7229 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7230 // 0 == any inventory type (not wand then)
7232 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7236 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7237 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7238 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7239 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7240 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7243 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7244 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7245 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7246 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7248 // .. taken pct: scripted (increases damage of * against targets *)
7249 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7250 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7252 switch((*i
)->GetModifier()->m_miscvalue
)
7255 case 4920: case 4919:
7256 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7257 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7261 // .. taken pct: dummy auras
7262 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7263 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7265 switch((*i
)->GetSpellProto()->SpellIconID
)
7269 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7271 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7273 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7274 if (mod
< (*i
)->GetModifier()->m_amount
)
7275 mod
= (*i
)->GetModifier()->m_amount
;
7276 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7281 for(int j
=0;j
<3;j
++)
7283 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7285 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7293 // Distribute Damage over multiple effects, reduce by AoE
7294 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7296 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7297 for(int j
= 0; j
< 3; ++j
)
7299 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7300 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7307 switch(spellProto
->SpellFamilyName
)
7309 case SPELLFAMILY_MAGE
:
7310 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7311 if(spellProto
->Id
==12654)
7316 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7318 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7319 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7320 TakenTotalMod
*= 3.0f
;
7322 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7323 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7325 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7326 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7328 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7329 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7332 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7335 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7339 // Arcane Missiles triggered spell
7340 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7344 // Blizzard triggered spell
7345 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7350 case SPELLFAMILY_WARLOCK
:
7352 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7354 CastingTime
= 2800; // 80% from +shadow damage
7355 DoneTotalMod
= 1.0f
;
7356 TakenTotalMod
= 1.0f
;
7359 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7361 CastingTime
= 3360; // 96% from +shadow damage
7362 DoneTotalMod
= 1.0f
;
7363 TakenTotalMod
= 1.0f
;
7365 // Soul Fire - 115% of Fire Damage
7366 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7370 // Curse of Agony - 120% of Shadow Damage
7371 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7375 // Drain Mana - 0% of Shadow Damage
7376 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7380 // Drain Soul 214.3%
7381 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7386 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7388 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7390 // Unstable Affliction - 180%
7391 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7396 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7401 case SPELLFAMILY_PALADIN
:
7402 // Consecration - 95% of Holy Damage
7403 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7408 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7409 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7411 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7412 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7414 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7415 CastingTime
= uint32(wspeed
*3500*0.102f
);
7417 CastingTime
= uint32(wspeed
*3500*0.098f
);
7419 // Judgement of Righteousness - 73%
7420 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7424 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7425 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7430 // Holy shield - 5% of Holy Damage
7431 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7435 // Blessing of Sanctuary - 0%
7436 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7440 // Seal of Righteousness trigger - already computed for parent spell
7441 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7446 case SPELLFAMILY_SHAMAN
:
7448 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7450 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7451 CastingTime
= 749; // ignore CastingTime and use as modifier
7452 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7453 CastingTime
= 280; // ignore CastingTime and use as modifier
7454 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7455 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7457 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7458 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7459 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7461 case SPELLFAMILY_PRIEST
:
7462 // Mana Burn - 0% of Shadow Damage
7463 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7467 // Mind Flay - 59% of Shadow Damage
7468 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7472 // Holy Fire - 86.71%, DoT - 16.5%
7473 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7475 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7476 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7478 // Shadowguard - 28% per charge
7479 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7483 // Touch of Weakeness - 10%
7484 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7488 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7489 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7494 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7499 case SPELLFAMILY_DRUID
:
7500 // Hurricane triggered spell
7501 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7506 case SPELLFAMILY_WARRIOR
:
7507 case SPELLFAMILY_HUNTER
:
7508 case SPELLFAMILY_ROGUE
:
7515 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7517 // Spellmod SpellDamage
7518 float SpellModSpellDamage
= 100.0f
;
7520 if(Player
* modOwner
= GetSpellModOwner())
7521 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7523 SpellModSpellDamage
/= 100.0f
;
7525 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7526 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7528 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7530 // Add flat bonus from spell damage versus
7531 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7533 // apply spellmod to Done damage
7534 if(Player
* modOwner
= GetSpellModOwner())
7535 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7537 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7539 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7540 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7542 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7545 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7547 int32 DoneAdvertisedBenefit
= 0;
7550 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7551 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7552 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7553 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7554 // -1 == any item class (not wand then)
7555 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7556 // 0 == any inventory type (not wand then)
7557 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7559 if (GetTypeId() == TYPEID_PLAYER
)
7561 // Damage bonus from stats
7562 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7563 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7565 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7567 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7568 uint8 eff
= (*i
)->GetEffIndex();
7570 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7571 Stats usedStat
= STAT_INTELLECT
;
7572 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7573 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7575 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7578 // ... and attack power
7579 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7580 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7581 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7582 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7585 return DoneAdvertisedBenefit
;
7588 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7590 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7592 int32 TakenAdvertisedBenefit
= 0;
7593 // ..done (for creature type by mask) in taken
7594 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7595 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7596 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7597 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7600 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7601 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7602 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7603 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7605 return TakenAdvertisedBenefit
;
7608 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7610 // not criting spell
7611 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7614 float crit_chance
= 0.0f
;
7615 switch(spellProto
->DmgClass
)
7617 case SPELL_DAMAGE_CLASS_NONE
:
7619 case SPELL_DAMAGE_CLASS_MAGIC
:
7621 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7623 // For other schools
7624 else if (GetTypeId() == TYPEID_PLAYER
)
7625 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7628 crit_chance
= m_baseSpellCritChance
;
7629 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7632 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7634 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7635 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7636 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7637 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7638 // Modify by player victim resilience
7639 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7640 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7641 // scripted (increase crit chance ... against ... target by x%
7642 if(pVictim
->isFrozen()) // Shatter
7644 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7645 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7647 switch((*i
)->GetModifier()->m_miscvalue
)
7649 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7650 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7651 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7652 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7653 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7660 case SPELL_DAMAGE_CLASS_MELEE
:
7661 case SPELL_DAMAGE_CLASS_RANGED
:
7665 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7666 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7667 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7675 // only players use intelligence for critical chance computations
7676 if(Player
* modOwner
= GetSpellModOwner())
7677 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7679 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7680 if (roll_chance_f(crit_chance
))
7685 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7687 // Calculate critical bonus
7689 switch(spellProto
->DmgClass
)
7691 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7692 case SPELL_DAMAGE_CLASS_RANGED
:
7693 // TODO: write here full calculation for melee/ranged spells
7694 crit_bonus
= damage
;
7697 crit_bonus
= damage
/ 2; // for spells is 50%
7701 // adds additional damage to crit_bonus (from talents)
7702 if(Player
* modOwner
= GetSpellModOwner())
7703 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7707 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7708 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7712 damage
+= crit_bonus
;
7717 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7719 // For totems get healing bonus from owner (statue isn't totem in fact)
7720 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7721 if(Unit
* owner
= GetOwner())
7722 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7726 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7727 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7728 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7729 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7732 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7733 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7736 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7738 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7739 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7741 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7742 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7744 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
7747 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7748 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7750 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7751 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7756 float ActualBenefit
= 0.0f
;
7758 if (AdvertisedBenefit
!= 0)
7760 // Healing over Time spells
7761 float DotFactor
= 1.0f
;
7762 if(damagetype
== DOT
)
7764 int32 DotDuration
= GetSpellDuration(spellProto
);
7768 if(DotDuration
> 30000) DotDuration
= 30000;
7769 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7771 for(int j
= 0; j
< 3; j
++)
7773 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7774 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7775 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7782 if(spellProto
->EffectAmplitude
[x
] != 0)
7783 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7785 AdvertisedBenefit
/= DotTicks
;
7789 // distribute healing to all effects, reduce AoE damage
7790 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7792 // 0% bonus for damage and healing spells for leech spells from healing bonus
7793 for(int j
= 0; j
< 3; ++j
)
7795 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7796 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7804 switch (spellProto
->SpellFamilyName
)
7806 case SPELLFAMILY_SHAMAN
:
7807 // Healing stream from totem (add 6% per tick from hill bonus owner)
7808 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7810 // Earth Shield 30% per charge
7811 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7814 case SPELLFAMILY_DRUID
:
7816 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7818 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7819 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7821 // Tranquility triggered spell
7822 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7825 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7828 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7830 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7831 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7834 case SPELLFAMILY_PRIEST
:
7836 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7839 case SPELLFAMILY_PALADIN
:
7840 // Seal and Judgement of Light
7841 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7844 case SPELLFAMILY_WARRIOR
:
7845 case SPELLFAMILY_ROGUE
:
7846 case SPELLFAMILY_HUNTER
:
7851 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7853 // Spellmod SpellDamage
7854 float SpellModSpellDamage
= 100.0f
;
7856 if(Player
* modOwner
= GetSpellModOwner())
7857 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7859 SpellModSpellDamage
/= 100.0f
;
7861 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7864 // use float as more appropriate for negative values and percent applying
7865 float heal
= healamount
+ ActualBenefit
;
7867 // TODO: check for ALL/SPELLS type
7868 // Healing done percent
7869 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7870 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7871 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7873 // apply spellmod to Done amount
7874 if(Player
* modOwner
= GetSpellModOwner())
7875 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7877 // Healing Wave cast
7878 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7880 // Search for Healing Way on Victim (stack up to 3 time)
7882 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7883 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7884 if((*itr
)->GetId() == 29203)
7885 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7888 heal
= heal
* (100 + pctMod
) / 100;
7891 // Healing taken percent
7892 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7894 heal
*= (100.0f
+ minval
) / 100.0f
;
7896 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7898 heal
*= (100.0f
+ maxval
) / 100.0f
;
7900 if (heal
< 0) heal
= 0;
7902 return uint32(heal
);
7905 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7907 int32 AdvertisedBenefit
= 0;
7909 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7910 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7911 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7912 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7914 // Healing bonus of spirit, intellect and strength
7915 if (GetTypeId() == TYPEID_PLAYER
)
7917 // Healing bonus from stats
7918 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7919 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7921 // stat used dependent from misc value (stat index)
7922 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7923 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7926 // ... and attack power
7927 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7928 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7929 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7930 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7932 return AdvertisedBenefit
;
7935 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7937 int32 AdvertisedBenefit
= 0;
7938 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
7939 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7940 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7941 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7942 return AdvertisedBenefit
;
7945 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
7947 // no charges dependent checks
7948 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
7949 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
7950 if(itr
->type
& shoolMask
)
7953 // charges dependent checks
7954 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
7955 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
7957 if(itr
->type
& shoolMask
)
7961 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
7962 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
7964 if((*auraItr
)->GetId()==itr
->spellId
)
7966 if((*auraItr
)->m_procCharges
> 0)
7968 --(*auraItr
)->m_procCharges
;
7969 if((*auraItr
)->m_procCharges
==0)
7970 RemoveAurasDueToSpell(itr
->spellId
);
7983 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
7990 //FIX ME this hack: don't get feared if stunned
7991 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
7993 if ( hasUnitState(UNIT_STAT_STUNNED
) )
7997 // not have spells with charges currently
7998 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
7999 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8000 if(itr
->type
== spellInfo
->Dispel
)
8003 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
)) // unaffected by school immunity
8005 // not have spells with charges currently
8006 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8007 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8008 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8009 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8013 // charges dependent checks
8015 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8016 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8018 if(itr
->type
== spellInfo
->Mechanic
)
8022 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8023 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8025 if((*auraItr
)->GetId()==itr
->spellId
)
8027 if((*auraItr
)->m_procCharges
> 0)
8029 --(*auraItr
)->m_procCharges
;
8030 if((*auraItr
)->m_procCharges
==0)
8031 RemoveAurasDueToSpell(itr
->spellId
);
8044 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8046 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8047 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8048 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8049 if(itr
->type
== effect
)
8052 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8053 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8054 if(itr
->type
== mechanic
)
8060 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8065 uint32 family
= spellInfo
->SpellFamilyName
;
8066 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8068 if((family
== 5 && flags
== 256) || //Searing Pain
8069 (family
== 6 && flags
== 8192) || //Mind Blast
8070 (family
== 11 && flags
== 1048576)) //Earth Shock
8076 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8084 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8086 // Taken/Done fixed damage bonus auras
8087 int32 DoneFlatBenefit
= 0;
8088 int32 TakenFlatBenefit
= 0;
8090 // ..done (for creature type by mask) in taken
8091 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8092 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8093 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8094 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8097 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8099 // ..done (base at attack power for marked target and base at attack power for creature type)
8101 if(attType
== RANGED_ATTACK
)
8103 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8105 // ..done (base at attack power and creature type)
8106 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8107 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8108 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8109 APbonus
+= (*i
)->GetModifier()->m_amount
;
8113 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8115 // ..done (base at attack power and creature type)
8116 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8117 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8118 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8119 APbonus
+= (*i
)->GetModifier()->m_amount
;
8122 if (APbonus
!=0) // Can be negative
8124 bool normalized
= false;
8127 for (uint8 i
= 0; i
<3;i
++)
8129 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8137 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8141 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8142 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8143 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8144 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8146 if(attType
!=RANGED_ATTACK
)
8147 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8149 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8151 // Done/Taken total percent damage auras
8152 float DoneTotalMod
= 1;
8153 float TakenTotalMod
= 1;
8156 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8157 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8159 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8160 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8161 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8162 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8165 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8166 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8167 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8168 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8170 // .. taken pct: dummy auras
8171 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8172 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8174 switch((*i
)->GetSpellProto()->SpellIconID
)
8178 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8180 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8182 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8183 if (mod
< (*i
)->GetModifier()->m_amount
)
8184 mod
= (*i
)->GetModifier()->m_amount
;
8185 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8190 if(spellProto
==NULL
)
8192 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8193 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8194 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8199 // .. taken pct: class scripts
8200 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8201 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8203 switch((*i
)->GetMiscValue())
8205 case 6427: case 6428: // Dirty Deeds
8206 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8208 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8209 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8211 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8215 // effect 0 have expected value but in negative state
8216 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8222 if(attType
!= RANGED_ATTACK
)
8224 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8225 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8226 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8230 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8231 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8232 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8235 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8237 // apply spellmod to Done damage
8240 if(Player
* modOwner
= GetSpellModOwner())
8241 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8244 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8246 // bonus result can be negative
8247 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8250 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8254 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8257 if(itr
->type
== type
)
8259 m_spellImmune
[op
].erase(itr
);
8260 next
= m_spellImmune
[op
].begin();
8264 Immune
.spellId
= spellId
;
8266 m_spellImmune
[op
].push_back(Immune
);
8270 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8272 if(itr
->spellId
== spellId
)
8274 m_spellImmune
[op
].erase(itr
);
8282 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8284 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8286 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8287 RemoveAurasWithDispelType(type
);
8290 float Unit::GetWeaponProcChance() const
8292 // normalized proc chance for weapon attack speed
8294 if(isAttackReady(BASE_ATTACK
))
8295 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8296 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8297 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8301 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8303 // proc per minute chance calculation
8304 if (PPM
<= 0) return 0.0f
;
8305 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8309 void Unit::Mount(uint32 mount
)
8314 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8316 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8318 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8321 if(GetTypeId() == TYPEID_PLAYER
)
8323 Pet
* pet
= GetPet();
8326 if(pet
->isControlled())
8328 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8329 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8332 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8335 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8339 void Unit::Unmount()
8344 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8346 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8347 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8349 // only resummon old pet if the player is already added to a map
8350 // this prevents adding a pet to a not created map which would otherwise cause a crash
8351 // (it could probably happen when logging in after a previous crash)
8352 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8354 Pet
* NewPet
= new Pet
;
8355 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8358 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8362 void Unit::SetInCombatWith(Unit
* enemy
)
8364 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8367 SetInCombatState(true);
8372 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8374 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8375 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8377 SetInCombatState(true);
8381 SetInCombatState(false);
8384 void Unit::SetInCombatState(bool PvP
)
8386 // only alive units can be in combat
8391 m_CombatTimer
= 5000;
8392 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8394 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8395 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8398 void Unit::ClearInCombat()
8401 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8403 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8404 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8406 // Player's state will be cleared in Player::UpdateContestedPvP
8407 if(GetTypeId()!=TYPEID_PLAYER
)
8408 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8411 bool Unit::isTargetableForAttack() const
8413 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8416 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8419 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8422 int32
Unit::ModifyHealth(int32 dVal
)
8429 int32 curHealth
= (int32
)GetHealth();
8431 int32 val
= dVal
+ curHealth
;
8438 int32 maxHealth
= (int32
)GetMaxHealth();
8443 gain
= val
- curHealth
;
8445 else if(curHealth
!= maxHealth
)
8447 SetHealth(maxHealth
);
8448 gain
= maxHealth
- curHealth
;
8454 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8461 int32 curPower
= (int32
)GetPower(power
);
8463 int32 val
= dVal
+ curPower
;
8470 int32 maxPower
= (int32
)GetMaxPower(power
);
8474 SetPower(power
,val
);
8475 gain
= val
- curPower
;
8477 else if(curPower
!= maxPower
)
8479 SetPower(power
,maxPower
);
8480 gain
= maxPower
- curPower
;
8486 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
8491 // Always can see self
8495 // player visible for other player if not logout and at same transport
8496 // including case when player is out of world
8497 bool at_same_transport
=
8498 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8499 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8500 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8501 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8504 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8507 // forbidden to seen (at GM respawn command)
8508 if(m_Visibility
==VISIBILITY_RESPAWN
)
8511 // always seen by owner
8512 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8515 // Grid dead/alive checks
8516 if( u
->GetTypeId()==TYPEID_PLAYER
)
8518 // non visible at grid for any stealth state
8519 if(!IsVisibleInGridForPlayer((Player
*)u
))
8522 // if player is dead then he can't detect anyone in any cases
8528 // all dead creatures/players not visible for any creatures
8529 if(!u
->isAlive() || !isAlive())
8533 // different visible distance checks
8534 if(u
->isInFlight()) // what see player in flight
8536 // use object grey distance for all (only see objects any way)
8537 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8540 else if(!isAlive()) // distance for show body
8542 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
8545 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8547 if(u
->GetTypeId()==TYPEID_PLAYER
)
8549 // Players far than max visible distance for player or not in our map are not visible too
8550 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8555 // Units far than max visible distance for creature or not in our map are not visible too
8556 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8560 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8562 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8563 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8566 else // distance for show creature
8568 // Units far than max visible distance for creature or not in our map are not visible too
8569 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
8573 // Visible units, always are visible for all units, except for units under invisibility
8574 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8577 // GMs see any players, not higher GMs and all units
8578 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8580 if(GetTypeId() == TYPEID_PLAYER
)
8581 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8586 // non faction visibility non-breakable for non-GMs
8587 if (m_Visibility
== VISIBILITY_OFF
)
8591 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8593 // detectable invisibility case
8595 // Invisible units, always are visible for units under same invisibility type
8596 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8597 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8598 u
->canDetectInvisibilityOf(this) ||
8599 // Units that can detect invisibility always are visible for units that can be detected
8600 canDetectInvisibilityOf(u
) ))
8605 // special cases for always overwrite invisibility/stealth
8606 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8609 if (!u
->IsHostileTo(this))
8611 // 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)
8612 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8614 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8617 // else apply same rules as for hostile case (detecting check for stealth)
8623 // Hunter mark functionality
8624 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8625 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8626 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8629 // else apply detecting check for stealth
8632 // none other cases for detect invisibility, so invisible
8636 // else apply stealth detecting check
8639 // unit got in stealth in this moment and must ignore old detected state
8640 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8643 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8644 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8647 // NOW ONLY STEALTH CASE
8649 // stealth and detected and visible for some seconds
8650 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8653 //if in non-detect mode then invisible for unit
8659 // If is attacked then stealth is lost, some creature can use stealth too
8660 if( !getAttackers().empty() )
8663 // If there is collision rogue is seen regardless of level difference
8664 // TODO: check sizes in DB
8665 float distance
= GetDistance(u
);
8666 if (distance
< 0.24f
)
8669 //If a mob or player is stunned he will not be able to detect stealth
8670 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8673 // Creature can detect target only in aggro radius
8674 if(u
->GetTypeId() != TYPEID_PLAYER
)
8676 //Always invisible from back and out of aggro range
8677 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8683 //Always invisible from back
8684 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8689 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8690 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8692 //Calculation if target is in front
8694 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8695 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8697 //Visible distance is modified by
8698 //-Level Diff (every level diff = 1.0f in visible distance)
8699 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8701 //This allows to check talent tree and will add addition stealth dependent on used points)
8702 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8706 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8707 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8708 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8710 if(distance
> visibleDistance
)
8714 // Now check is target visible with LoS
8716 u
->GetPosition(ox
,oy
,oz
);
8717 return IsWithinLOS(ox
,oy
,oz
);
8720 void Unit::SetVisibility(UnitVisibility x
)
8726 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
8728 if(GetTypeId()==TYPEID_PLAYER
)
8729 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8731 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8735 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8737 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8739 for(uint32 i
= 0; i
< 10; ++i
)
8741 if(((1 << i
) & mask
)==0)
8744 // find invisibility level
8745 uint32 invLevel
= 0;
8746 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8747 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8748 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8749 invLevel
= (*itr
)->GetModifier()->m_amount
;
8751 // find invisibility detect level
8752 uint32 detectLevel
= 0;
8753 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8754 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8755 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8756 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8758 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8760 detectLevel
= ((Player
*)this)->GetDrunkValue();
8763 if(invLevel
<= detectLevel
)
8771 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8773 int32 main_speed_mod
= 0;
8774 float stack_bonus
= 1.0f
;
8775 float non_stack_bonus
= 1.0f
;
8783 if (IsMounted()) // Use on mount auras
8785 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8786 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8787 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8791 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8792 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8793 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8801 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8808 if (IsMounted()) // Use on mount auras
8809 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8810 else // Use not mount (shapeshift for example) auras (should stack)
8811 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8812 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8813 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8819 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8823 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8824 // now we ready for speed calculation
8825 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8833 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8834 // TODO: possible affect only on MOVE_RUN
8835 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8837 // Use speed from aura
8838 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8839 if (speed
> max_speed
)
8848 // Apply strongest slow aura mod to speed
8849 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8851 speed
*=(100.0f
+ slow
)/100.0f
;
8852 SetSpeed(mtype
, speed
, forced
);
8855 float Unit::GetSpeed( UnitMoveType mtype
) const
8857 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8860 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8865 // Update speed only on change
8866 if (m_speed_rate
[mtype
] == rate
)
8869 m_speed_rate
[mtype
] = rate
;
8871 propagateSpeedChange();
8873 // Send speed change packet only for player
8874 if (GetTypeId()!=TYPEID_PLAYER
)
8883 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8886 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8889 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8892 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8895 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8898 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+1+4+4+4+4+4+4+4);
8901 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8904 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+1+4+4+4+4+4+4+4);
8907 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8911 data
.append(GetPackGUID());
8912 data
<< uint32(0); //movement flags
8913 data
<< uint8(0); //unk
8914 data
<< uint32(getMSTime());
8915 data
<< float(GetPositionX());
8916 data
<< float(GetPositionY());
8917 data
<< float(GetPositionZ());
8918 data
<< float(GetOrientation());
8919 data
<< uint32(0); //flag unk
8920 data
<< float(GetSpeed(mtype
));
8921 SendMessageToSet( &data
, true );
8925 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8926 // and do it only for real sent packets and use run for run/mounted as client expected
8927 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
8931 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
8934 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
8937 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
8940 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
8943 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
8946 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
8949 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
8952 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
8955 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8958 data
.append(GetPackGUID());
8960 if (mtype
== MOVE_RUN
)
8961 data
<< uint8(0); // new 2.1.0
8962 data
<< float(GetSpeed(mtype
));
8963 SendMessageToSet( &data
, true );
8965 if(Pet
* pet
= GetPet())
8966 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
8969 void Unit::SetHover(bool on
)
8972 CastSpell(this,11010,true);
8974 RemoveAurasDueToSpell(11010);
8977 void Unit::setDeathState(DeathState s
)
8979 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
8983 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
8985 if(IsNonMeleeSpellCasted(false))
8986 InterruptNonMeleeSpells(false);
8991 RemoveAllAurasOnDeath();
8992 UnsummonAllTotems();
8994 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
8995 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
8996 // remove aurastates allowing special moves
8997 ClearAllReactives();
8998 ClearDiminishings();
9000 else if(s
== JUST_ALIVED
)
9002 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9005 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9007 //_ApplyAllAuraMods();
9012 /*########################################
9014 ######## AGGRO SYSTEM ########
9016 ########################################*/
9017 bool Unit::CanHaveThreatList() const
9019 // only creatures can have threat list
9020 if( GetTypeId() != TYPEID_UNIT
)
9023 // only alive units can have threat list
9027 // pets and totems can not have threat list
9028 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() )
9034 //======================================================================
9036 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9038 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9041 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9043 return threat
* m_threatModifier
[school
];
9046 //======================================================================
9048 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9050 // Only mobs can manage threat lists
9051 if(CanHaveThreatList())
9052 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9055 //======================================================================
9057 void Unit::DeleteThreatList()
9059 m_ThreatManager
.clearReferences();
9062 //======================================================================
9064 void Unit::TauntApply(Unit
* taunter
)
9066 assert(GetTypeId()== TYPEID_UNIT
);
9068 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9071 if(!CanHaveThreatList())
9074 Unit
*target
= getVictim();
9075 if(target
&& target
== taunter
)
9078 SetInFront(taunter
);
9079 if (((Creature
*)this)->AI())
9080 ((Creature
*)this)->AI()->AttackStart(taunter
);
9082 m_ThreatManager
.tauntApply(taunter
);
9085 //======================================================================
9087 void Unit::TauntFadeOut(Unit
*taunter
)
9089 assert(GetTypeId()== TYPEID_UNIT
);
9091 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9094 if(!CanHaveThreatList())
9097 Unit
*target
= getVictim();
9098 if(!target
|| target
!= taunter
)
9101 if(m_ThreatManager
.isThreatListEmpty())
9103 if(((Creature
*)this)->AI())
9104 ((Creature
*)this)->AI()->EnterEvadeMode();
9108 m_ThreatManager
.tauntFadeOut(taunter
);
9109 target
= m_ThreatManager
.getHostilTarget();
9111 if (target
&& target
!= taunter
)
9114 if (((Creature
*)this)->AI())
9115 ((Creature
*)this)->AI()->AttackStart(target
);
9119 //======================================================================
9121 bool Unit::SelectHostilTarget()
9123 //function provides main threat functionality
9124 //next-victim-selection algorithm and evade mode are called
9125 //threat list sorting etc.
9127 assert(GetTypeId()== TYPEID_UNIT
);
9128 Unit
* target
= NULL
;
9130 //This function only useful once AI has been initialized
9131 if (!((Creature
*)this)->AI())
9134 if(!m_ThreatManager
.isThreatListEmpty())
9136 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9138 target
= m_ThreatManager
.getHostilTarget();
9144 if(!hasUnitState(UNIT_STAT_STUNNED
))
9146 ((Creature
*)this)->AI()->AttackStart(target
);
9150 // no target but something prevent go to evade mode
9151 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9154 // last case when creature don't must go to evade mode:
9155 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9156 // for example at owner command to pet attack some far away creature
9157 // Note: creature not have targeted movement generator but have attacker in this case
9158 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9160 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9162 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9167 // enter in evade mode in other case
9168 ((Creature
*)this)->AI()->EnterEvadeMode();
9173 //======================================================================
9174 //======================================================================
9175 //======================================================================
9177 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9179 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9181 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9183 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9184 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9185 level
= spellProto
->maxLevel
;
9187 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9188 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9189 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9190 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9191 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9193 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9194 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9195 int32 value
= basePoints
+ randvalue
;
9197 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9198 value
+= (int32
)(comboDamage
* comboPoints
);
9200 if(Player
* modOwner
= GetSpellModOwner())
9202 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9203 switch(effect_index
)
9206 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9209 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9212 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9217 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9218 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9219 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9220 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9225 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9227 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9229 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9231 int32 minduration
= GetSpellDuration(spellProto
);
9232 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9236 if( minduration
!= -1 && minduration
!= maxduration
)
9237 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9239 duration
= minduration
;
9243 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9244 // Find total mod value (negative bonus)
9245 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9246 // Find max mod (negative bonus)
9247 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9249 int32 durationMod
= 0;
9250 // Select strongest negative mod
9251 if (durationMod_always
> durationMod_not_stack
)
9252 durationMod
= durationMod_not_stack
;
9254 durationMod
= durationMod_always
;
9256 if (durationMod
!= 0)
9257 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9259 if (duration
< 0) duration
= 0;
9265 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9267 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9269 if(i
->DRGroup
!= group
)
9273 return DIMINISHING_LEVEL_1
;
9276 return DIMINISHING_LEVEL_1
;
9278 // If last spell was casted more than 15 seconds ago - reset the count.
9279 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9281 i
->hitCount
= DIMINISHING_LEVEL_1
;
9282 return DIMINISHING_LEVEL_1
;
9284 // or else increase the count.
9287 return DiminishingLevels(i
->hitCount
);
9290 return DIMINISHING_LEVEL_1
;
9293 void Unit::IncrDiminishing(DiminishingGroup group
)
9295 // Checking for existing in the table
9296 bool IsExist
= false;
9297 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9299 if(i
->DRGroup
!= group
)
9303 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9310 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9313 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9315 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9318 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9319 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9321 // test pet/charm masters instead pets/charmeds
9322 Unit
const* targetOwner
= GetCharmerOrOwner();
9323 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9325 Unit
const* target
= targetOwner
? targetOwner
: this;
9326 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9328 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9334 // Some diminishings applies to mobs too (for example, Stun)
9335 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9337 DiminishingLevels diminish
= Level
;
9340 case DIMINISHING_LEVEL_1
: break;
9341 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9342 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9343 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9348 duration
= int32(duration
* mod
);
9351 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9353 // Checking for existing in the table
9354 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9356 if(i
->DRGroup
!= group
)
9359 i
->hitTime
= getMSTime();
9370 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9372 return ObjectAccessor::GetUnit(object
,guid
);
9375 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9377 return isVisibleForOrDetect(u
,false,inVisibleList
);
9380 uint32
Unit::GetCreatureType() const
9382 if(GetTypeId() == TYPEID_PLAYER
)
9384 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9385 if(ssEntry
&& ssEntry
->creatureType
> 0)
9386 return ssEntry
->creatureType
;
9388 return CREATURE_TYPE_HUMANOID
;
9391 return ((Creature
*)this)->GetCreatureInfo()->type
;
9394 /*#######################################
9396 ######## STAT SYSTEM ########
9398 #######################################*/
9400 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9402 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9404 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9410 switch(modifierType
)
9414 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9418 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9421 val
= (100.0f
+ amount
) / 100.0f
;
9422 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9429 if(!CanModifyStats())
9434 case UNIT_MOD_STAT_STRENGTH
:
9435 case UNIT_MOD_STAT_AGILITY
:
9436 case UNIT_MOD_STAT_STAMINA
:
9437 case UNIT_MOD_STAT_INTELLECT
:
9438 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9440 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9441 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9445 case UNIT_MOD_FOCUS
:
9446 case UNIT_MOD_ENERGY
:
9447 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9449 case UNIT_MOD_RESISTANCE_HOLY
:
9450 case UNIT_MOD_RESISTANCE_FIRE
:
9451 case UNIT_MOD_RESISTANCE_NATURE
:
9452 case UNIT_MOD_RESISTANCE_FROST
:
9453 case UNIT_MOD_RESISTANCE_SHADOW
:
9454 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9456 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9457 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9459 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9460 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9461 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9470 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9472 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9474 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9478 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9481 return m_auraModifiersGroup
[unitMod
][modifierType
];
9484 float Unit::GetTotalStatValue(Stats stat
) const
9486 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9488 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9491 // value = ((base_value * base_pct) + total_value) * total_pct
9492 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9493 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9494 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9495 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9500 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9502 if(unitMod
>= UNIT_MOD_END
)
9504 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9508 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9511 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9512 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9513 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9514 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9519 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9521 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9525 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9526 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9527 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9528 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9529 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9530 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9539 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9541 Stats stat
= STAT_STRENGTH
;
9545 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9546 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9547 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9548 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9549 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9558 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9560 Powers power
= POWER_MANA
;
9564 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
9565 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
9566 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
9567 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
9568 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
9577 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9579 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9581 float val
= GetTotalAuraModValue(unitMod
);
9588 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9590 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9593 return m_weaponDamage
[attType
][type
];
9596 void Unit::SetLevel(uint32 lvl
)
9598 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9601 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9602 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9605 void Unit::SetHealth(uint32 val
)
9607 uint32 maxHealth
= GetMaxHealth();
9611 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9614 if(GetTypeId() == TYPEID_PLAYER
)
9616 if(((Player
*)this)->GetGroup())
9617 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9619 else if(((Creature
*)this)->isPet())
9621 Pet
*pet
= ((Pet
*)this);
9622 if(pet
->isControlled())
9624 Unit
*owner
= GetOwner();
9625 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9626 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9631 void Unit::SetMaxHealth(uint32 val
)
9633 uint32 health
= GetHealth();
9634 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9637 if(GetTypeId() == TYPEID_PLAYER
)
9639 if(((Player
*)this)->GetGroup())
9640 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9642 else if(((Creature
*)this)->isPet())
9644 Pet
*pet
= ((Pet
*)this);
9645 if(pet
->isControlled())
9647 Unit
*owner
= GetOwner();
9648 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9649 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9657 void Unit::SetPower(Powers power
, uint32 val
)
9659 uint32 maxPower
= GetMaxPower(power
);
9663 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9666 if(GetTypeId() == TYPEID_PLAYER
)
9668 if(((Player
*)this)->GetGroup())
9669 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9671 else if(((Creature
*)this)->isPet())
9673 Pet
*pet
= ((Pet
*)this);
9674 if(pet
->isControlled())
9676 Unit
*owner
= GetOwner();
9677 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9678 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9681 // Update the pet's character sheet with happiness damage bonus
9682 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9684 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9689 void Unit::SetMaxPower(Powers power
, uint32 val
)
9691 uint32 cur_power
= GetPower(power
);
9692 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9695 if(GetTypeId() == TYPEID_PLAYER
)
9697 if(((Player
*)this)->GetGroup())
9698 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9700 else if(((Creature
*)this)->isPet())
9702 Pet
*pet
= ((Pet
*)this);
9703 if(pet
->isControlled())
9705 Unit
*owner
= GetOwner();
9706 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9707 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9712 SetPower(power
, val
);
9715 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9717 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9720 if(GetTypeId() == TYPEID_PLAYER
)
9722 if(((Player
*)this)->GetGroup())
9723 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9725 else if(((Creature
*)this)->isPet())
9727 Pet
*pet
= ((Pet
*)this);
9728 if(pet
->isControlled())
9730 Unit
*owner
= GetOwner();
9731 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9732 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9737 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9739 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9742 if(GetTypeId() == TYPEID_PLAYER
)
9744 if(((Player
*)this)->GetGroup())
9745 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9747 else if(((Creature
*)this)->isPet())
9749 Pet
*pet
= ((Pet
*)this);
9750 if(pet
->isControlled())
9752 Unit
*owner
= GetOwner();
9753 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9754 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9759 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9761 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9763 tAuraProcTriggerDamage
.push_back(aura
);
9765 tAuraProcTriggerDamage
.remove(aura
);
9768 uint32
Unit::GetCreatePowers( Powers power
) const
9770 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9773 case POWER_MANA
: return GetCreateMana();
9774 case POWER_RAGE
: return 1000;
9775 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9776 case POWER_ENERGY
: return 100;
9777 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9783 void Unit::AddToWorld()
9785 Object::AddToWorld();
9788 void Unit::RemoveFromWorld()
9793 RemoveNotOwnSingleTargetAuras();
9796 Object::RemoveFromWorld();
9799 void Unit::CleanupsBeforeDelete()
9801 if(m_uint32Values
) // only for fully created object
9803 InterruptNonMeleeSpells(true);
9804 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9806 ClearComboPointHolders();
9808 getHostilRefManager().setOnlineOfflineState(false);
9810 RemoveAllGameObjects();
9811 RemoveAllDynObjects();
9812 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9817 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9820 m_charmInfo
= new CharmInfo(charm
);
9824 CharmInfo::CharmInfo(Unit
* unit
)
9825 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9827 for(int i
=0; i
<4; ++i
)
9829 m_charmspells
[i
].spellId
= 0;
9830 m_charmspells
[i
].active
= ACT_DISABLED
;
9834 void CharmInfo::InitPetActionBar()
9836 // the first 3 SpellOrActions are attack, follow and stay
9837 for(uint32 i
= 0; i
< 3; i
++)
9839 PetActionBar
[i
].Type
= ACT_COMMAND
;
9840 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9842 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9843 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9845 for(uint32 i
=0; i
< 4; i
++)
9847 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9848 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9852 void CharmInfo::InitEmptyActionBar()
9854 for(uint32 x
= 1; x
< 10; ++x
)
9856 PetActionBar
[x
].Type
= ACT_CAST
;
9857 PetActionBar
[x
].SpellOrAction
= 0;
9859 PetActionBar
[0].Type
= ACT_COMMAND
;
9860 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9863 void CharmInfo::InitPossessCreateSpells()
9865 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9868 InitEmptyActionBar(); //charm action bar
9870 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9872 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9873 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9875 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
9879 void CharmInfo::InitCharmCreateSpells()
9881 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9883 InitEmptyActionBar();
9889 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9891 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9892 m_charmspells
[x
].spellId
= spellId
;
9897 if (IsPassiveSpell(spellId
))
9899 m_unit
->CastSpell(m_unit
, spellId
, true);
9900 m_charmspells
[x
].active
= ACT_PASSIVE
;
9904 ActiveStates newstate
;
9905 bool onlyselfcast
= true;
9906 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9908 if(!spellInfo
) onlyselfcast
= false;
9909 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9911 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9912 onlyselfcast
= false;
9915 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
9916 newstate
= ACT_DISABLED
;
9918 newstate
= ACT_CAST
;
9920 AddSpellToAB(0, spellId
, newstate
);
9925 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
9927 for(uint8 i
= 0; i
< 10; i
++)
9929 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
9931 PetActionBar
[i
].SpellOrAction
= newid
;
9934 if(newstate
== ACT_DECIDE
)
9935 PetActionBar
[i
].Type
= ACT_DISABLED
;
9937 PetActionBar
[i
].Type
= newstate
;
9946 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
9948 if(IsPassiveSpell(spellid
))
9951 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9953 if(spellid
== m_charmspells
[x
].spellId
)
9955 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
9960 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
9962 m_petnumber
= petnumber
;
9964 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
9966 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
9969 bool Unit::isFrozen() const
9971 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
9972 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
9973 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
9978 struct ProcTriggeredData
9980 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
9981 : triggeredByAura(_triggeredByAura
),
9982 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
9986 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
9987 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
9988 uint32 cooldown
; // possible hidden cooldown
9991 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
9993 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
9995 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
9997 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
9998 ProcTriggeredList procTriggered
;
10000 AuraList
const& auras
= GetAurasByType(*aur
);
10001 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10007 uint32 cooldown
; // returned at next line
10008 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10011 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10014 // Handle effects proceed this time
10015 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10017 // Some auras can be deleted in function called in this loop (except first, ofc)
10018 // Until storing auras in std::multimap to hard check deleting by another way
10019 if(i
!= procTriggered
.begin())
10021 bool found
= false;
10022 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10023 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10024 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10026 if(itr
->second
==i
->triggeredByAura
)
10035 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
);
10036 sLog
.outError("It can be deleted one from early processed auras:");
10037 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10038 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10039 sLog
.outError(" <end of list>");
10044 /// this is aura triggering code call
10045 Aura
* triggeredByAura
= i
->triggeredByAura
;
10047 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10048 /// used in speedup code check before check aura existance.
10049 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10051 /// success in event proccesing
10052 /// used in speedup code check before check aura existance.
10053 bool casted
= false;
10055 /// process triggered code
10058 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10060 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10061 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10062 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10065 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10067 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10068 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10069 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10070 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10074 case SPELL_AURA_DUMMY
:
10076 uint32 effect
= triggeredByAura
->GetEffIndex();
10077 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10078 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10079 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10082 case SPELL_AURA_PRAYER_OF_MENDING
:
10084 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10085 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10087 casted
= HandleMeandingAuraProc(triggeredByAura
);
10090 case SPELL_AURA_MOD_HASTE
:
10092 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10093 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10094 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10097 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10099 // nothing do, just charges counter
10100 // but count only in case appropriate school damage
10101 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10104 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10106 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s class script aura of spell %u)",
10107 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10108 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10113 // nothing do, just charges counter
10119 /// Update charge (aura can be removed by triggers)
10120 if(casted
&& triggeredByAuraWithCharges
)
10122 /// need re-found aura (can be dropped by triggers)
10123 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10124 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10125 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10127 if(itr
->second
== triggeredByAura
) // pointer still valid
10129 if(triggeredByAura
->m_procCharges
> 0)
10130 triggeredByAura
->m_procCharges
-= 1;
10132 triggeredByAura
->UpdateAuraCharges();
10139 /// Safely remove auras with zero charges
10140 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10143 if((*i
)->m_procCharges
== 0)
10145 RemoveAurasDueToSpell((*i
)->GetId());
10146 next
= auras
.begin();
10152 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10154 return SPELL_SCHOOL_MASK_NORMAL
;
10157 Player
* Unit::GetSpellModOwner()
10159 if(GetTypeId()==TYPEID_PLAYER
)
10160 return (Player
*)this;
10161 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10163 Unit
* owner
= GetOwner();
10164 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10165 return (Player
*)owner
;
10170 ///----------Pet responses methods-----------------
10171 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10173 Unit
*owner
= GetCharmerOrOwner();
10174 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10177 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10178 data
<< uint32(spellid
);
10179 data
<< uint8(msg
);
10180 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10183 void Unit::SendPetActionFeedback (uint8 msg
)
10185 Unit
* owner
= GetOwner();
10186 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10189 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10190 data
<< uint8(msg
);
10191 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10194 void Unit::SendPetTalk (uint32 pettalk
)
10196 Unit
* owner
= GetOwner();
10197 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10200 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10201 data
<< uint64(GetGUID());
10202 data
<< uint32(pettalk
);
10203 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10206 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10208 Unit
* owner
= GetOwner();
10209 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10212 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10213 data
<< uint64(GetGUID());
10214 data
<< uint8(0x0); // flags (0x1, 0x2)
10215 data
<< uint32(spellid
);
10216 data
<< uint32(cooltime
);
10218 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10221 void Unit::SendPetClearCooldown (uint32 spellid
)
10223 Unit
* owner
= GetOwner();
10224 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10227 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10228 data
<< uint32(spellid
);
10229 data
<< uint64(GetGUID());
10230 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10233 void Unit::SendPetAIReaction(uint64 guid
)
10235 Unit
* owner
= GetOwner();
10236 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10239 WorldPacket
data(SMSG_AI_REACTION
, 12);
10240 data
<< uint64(guid
) << uint32(00000002);
10241 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10244 ///----------End of Pet responses methods----------
10246 void Unit::StopMoving()
10248 clearUnitState(UNIT_STAT_MOVING
);
10250 // send explicit stop packet
10251 // rely on vmaps here because for example stormwind is in air
10252 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10253 //if (fabs(GetPositionZ() - z) < 2.0f)
10254 // Relocate(GetPositionX(), GetPositionY(), z);
10255 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10257 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10259 // update position and orientation;
10261 BuildHeartBeatMsg(&data
);
10262 SendMessageToSet(&data
,false);
10265 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10269 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10272 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10274 GetMotionMaster()->MovementExpired(false);
10275 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10277 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10279 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10283 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10285 GetMotionMaster()->MovementExpired(false);
10287 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10289 // restore appropriate movement generator
10291 GetMotionMaster()->MoveChase(getVictim());
10293 GetMotionMaster()->Initialize();
10295 // attack caster if can
10296 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10297 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10298 ((Creature
*)this)->AI()->AttackStart(caster
);
10302 if (GetTypeId() == TYPEID_PLAYER
)
10303 ((Player
*)this)->SetClientControl(this, !apply
);
10306 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10310 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10312 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10314 GetMotionMaster()->MoveConfused();
10318 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10320 GetMotionMaster()->MovementExpired(false);
10322 if (GetTypeId() == TYPEID_UNIT
)
10324 // if in combat restore movement generator
10326 GetMotionMaster()->MoveChase(getVictim());
10330 if(GetTypeId() == TYPEID_PLAYER
)
10331 ((Player
*)this)->SetClientControl(this, !apply
);
10334 bool Unit::IsSitState() const
10336 uint8 s
= getStandState();
10337 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10338 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10339 s
== PLAYER_STATE_SIT
;
10342 bool Unit::IsStandState() const
10344 uint8 s
= getStandState();
10345 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10348 void Unit::SetStandState(uint8 state
)
10350 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10352 if (IsStandState())
10353 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10355 if(GetTypeId()==TYPEID_PLAYER
)
10357 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10358 data
<< (uint8
)state
;
10359 ((Player
*)this)->GetSession()->SendPacket(&data
);
10363 bool Unit::IsPolymorphed() const
10365 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10368 void Unit::SetDisplayId(uint32 modelId
)
10370 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10372 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10374 Pet
*pet
= ((Pet
*)this);
10375 if(!pet
->isControlled())
10377 Unit
*owner
= GetOwner();
10378 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10379 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10383 void Unit::ClearComboPointHolders()
10385 while(!m_ComboPointHolders
.empty())
10387 uint32 lowguid
= *m_ComboPointHolders
.begin();
10389 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10390 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10391 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10393 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10397 void Unit::ClearAllReactives()
10400 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10401 m_reactiveTimer
[i
] = 0;
10403 if (HasAuraState( AURA_STATE_DEFENSE
))
10404 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10405 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10406 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10407 if (HasAuraState( AURA_STATE_CRIT
))
10408 ModifyAuraState(AURA_STATE_CRIT
, false);
10409 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10410 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10412 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10413 ((Player
*)this)->ClearComboPoints();
10416 void Unit::UpdateReactives( uint32 p_time
)
10418 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10420 ReactiveType reactive
= ReactiveType(i
);
10422 if(!m_reactiveTimer
[reactive
])
10425 if ( m_reactiveTimer
[reactive
] <= p_time
)
10427 m_reactiveTimer
[reactive
] = 0;
10429 switch ( reactive
)
10431 case REACTIVE_DEFENSE
:
10432 if (HasAuraState(AURA_STATE_DEFENSE
))
10433 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10435 case REACTIVE_HUNTER_PARRY
:
10436 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10437 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10439 case REACTIVE_CRIT
:
10440 if (HasAuraState(AURA_STATE_CRIT
))
10441 ModifyAuraState(AURA_STATE_CRIT
, false);
10443 case REACTIVE_HUNTER_CRIT
:
10444 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10445 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10447 case REACTIVE_OVERPOWER
:
10448 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10449 ((Player
*)this)->ClearComboPoints();
10457 m_reactiveTimer
[reactive
] -= p_time
;
10462 Unit
* Unit::SelectNearbyTarget() const
10464 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10466 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10467 cell
.SetNoCreate();
10469 std::list
<Unit
*> targets
;
10472 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10473 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10475 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10476 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10478 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10479 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10480 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *MapManager::Instance().GetMap(GetMapId(), this));
10483 // remove current target
10485 targets
.remove(getVictim());
10487 // remove not LoS targets
10488 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10490 if(!IsWithinLOSInMap(*tIter
))
10492 std::list
<Unit
*>::iterator tIter2
= tIter
;
10494 targets
.erase(tIter2
);
10500 // no appropriate targets
10501 if(targets
.empty())
10505 uint32 rIdx
= urand(0,targets
.size()-1);
10506 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10507 for(uint32 i
= 0; i
< rIdx
; ++i
)
10513 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10517 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10518 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10522 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10523 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10527 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10530 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10532 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10535 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10537 if (CastingTime
> 7000) CastingTime
= 7000;
10538 if (CastingTime
< 1500) CastingTime
= 1500;
10540 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10541 CastingTime
= 3500;
10543 int32 overTime
= 0;
10545 bool DirectDamage
= false;
10546 bool AreaEffect
= false;
10548 for ( uint32 i
=0; i
<3;i
++)
10550 switch ( spellProto
->Effect
[i
] )
10552 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10553 case SPELL_EFFECT_POWER_DRAIN
:
10554 case SPELL_EFFECT_HEALTH_LEECH
:
10555 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10556 case SPELL_EFFECT_POWER_BURN
:
10557 case SPELL_EFFECT_HEAL
:
10558 DirectDamage
= true;
10560 case SPELL_EFFECT_APPLY_AURA
:
10561 switch ( spellProto
->EffectApplyAuraName
[i
] )
10563 case SPELL_AURA_PERIODIC_DAMAGE
:
10564 case SPELL_AURA_PERIODIC_HEAL
:
10565 case SPELL_AURA_PERIODIC_LEECH
:
10566 if ( GetSpellDuration(spellProto
) )
10567 overTime
= GetSpellDuration(spellProto
);
10570 // -5% per additional effect
10578 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10582 // Combined Spells with Both Over Time and Direct Damage
10583 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10585 // mainly for DoTs which are 3500 here otherwise
10586 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10587 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10588 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10589 // Portion to Over Time
10590 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10592 if ( damagetype
== DOT
)
10593 CastingTime
= uint32(CastingTime
* PtOT
);
10594 else if ( PtOT
< 1.0f
)
10595 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10600 // Area Effect Spells receive only half of bonus
10604 // -5% of total per any additional effect
10605 for ( uint8 i
=0; i
<effects
; ++i
)
10607 if ( CastingTime
> 175 )
10609 CastingTime
-= 175;
10618 return CastingTime
;
10621 void Unit::UpdateAuraForGroup(uint8 slot
)
10623 if(GetTypeId() == TYPEID_PLAYER
)
10625 Player
* player
= (Player
*)this;
10626 if(player
->GetGroup())
10628 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10629 player
->SetAuraUpdateMask(slot
);
10632 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10634 Pet
*pet
= ((Pet
*)this);
10635 if(pet
->isControlled())
10637 Unit
*owner
= GetOwner();
10638 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10640 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10641 pet
->SetAuraUpdateMask(slot
);
10647 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10649 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10650 return float(GetAttackTime(attType
))/1000.0f
;
10652 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10654 return 2.4; // fist attack
10656 switch (Weapon
->GetProto()->InventoryType
)
10658 case INVTYPE_2HWEAPON
:
10660 case INVTYPE_RANGED
:
10661 case INVTYPE_RANGEDRIGHT
:
10662 case INVTYPE_THROWN
:
10664 case INVTYPE_WEAPON
:
10665 case INVTYPE_WEAPONMAINHAND
:
10666 case INVTYPE_WEAPONOFFHAND
:
10668 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10672 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10674 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10675 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10676 if ((*itr
)->GetId() == spell_id
)
10682 bool Unit::IsUnderLastManaUseEffect() const
10684 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10687 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10689 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10691 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10694 player
->SetContestedPvPTimer(30000);
10695 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10697 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10698 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10699 // call MoveInLineOfSight for nearby contested guards
10700 SetVisibility(GetVisibility());
10702 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10704 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10705 // call MoveInLineOfSight for nearby contested guards
10706 SetVisibility(GetVisibility());
10710 void Unit::AddPetAura(PetAura
const* petSpell
)
10712 m_petAuras
.insert(petSpell
);
10713 if(Pet
* pet
= GetPet())
10714 pet
->CastPetAura(petSpell
);
10717 void Unit::RemovePetAura(PetAura
const* petSpell
)
10719 m_petAuras
.erase(petSpell
);
10720 if(Pet
* pet
= GetPet())
10721 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10724 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10726 Pet
* pet
= new Pet(HUNTER_PET
);
10728 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10734 pet
->SetUInt64Value(UNIT_FIELD_SUMMONEDBY
, GetGUID());
10735 pet
->SetUInt64Value(UNIT_FIELD_CREATEDBY
, GetGUID());
10736 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
,getFaction());
10737 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10739 if(!pet
->InitStatsForLevel(creatureTarget
->getLevel()))
10741 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10746 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10747 // this enables pet details window (Shift+P)
10748 pet
->AIM_Initialize();
10749 pet
->InitPetCreateSpells();
10750 pet
->SetHealth(pet
->GetMaxHealth());
10755 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10757 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10759 if(!spellProcEvent
)
10761 // used to prevent spam in log about same non-handled spells
10762 static std::set
<uint32
> nonHandledSpellProcSet
;
10764 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10766 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10767 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10770 // spell.dbc use totally different flags, that only can create problems if used.
10774 // Check spellProcEvent data requirements
10775 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10778 // Check if current equipment allows aura to proc
10779 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10781 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10783 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10785 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10788 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10790 // Check if player is wearing shield
10791 Item
*item
= ((Player
*)this)->GetShield(true);
10792 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10797 float chance
= (float)spellProto
->procChance
;
10799 if(Player
* modOwner
= GetSpellModOwner())
10800 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10802 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10804 uint32 WeaponSpeed
= GetAttackTime(attType
);
10805 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10808 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10809 return roll_chance_f(chance
);
10812 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10814 // aura can be deleted at casts
10815 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10816 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10817 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10818 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10821 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10823 // current aura expire
10824 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10826 // next target selection
10827 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10830 if (spellProto
->EffectRadiusIndex
[effIdx
])
10831 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10833 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10835 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10837 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10839 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10841 // aura will applied from caster, but spell casted from current aura holder
10842 SpellModifier
*mod
= new SpellModifier
;
10843 mod
->op
= SPELLMOD_CHARGES
;
10844 mod
->value
= jumps
-5; // negative
10845 mod
->type
= SPELLMOD_FLAT
;
10846 mod
->spellId
= spellProto
->Id
;
10847 mod
->effectId
= effIdx
;
10848 mod
->lastAffected
= NULL
;
10849 mod
->mask
= spellProto
->SpellFamilyFlags
;
10852 caster
->AddSpellMod(mod
, true);
10853 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10854 caster
->AddSpellMod(mod
, false);
10860 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);