2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
25 #include "ObjectMgr.h"
33 #include "SpellAuras.h"
34 #include "MapManager.h"
35 #include "ObjectAccessor.h"
36 #include "CreatureAI.h"
41 #include "BattleGround.h"
42 #include "InstanceSaveMgr.h"
43 #include "GridNotifiersImpl.h"
49 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
53 1.25f
, // MOVE_RUN_BACK
54 4.722222f
, // MOVE_SWIM
55 4.5f
, // MOVE_SWIM_BACK
56 3.141594f
, // MOVE_TURN_RATE
58 4.5f
, // MOVE_FLIGHT_BACK
59 3.14f
// MOVE_PITCH_RATE
62 // auraTypes contains attacker auras capable of proc'ing cast auras
63 static Unit::AuraTypeSet
GenerateAttakerProcCastAuraTypes()
65 static Unit::AuraTypeSet auraTypes
;
66 auraTypes
.insert(SPELL_AURA_DUMMY
);
67 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
68 auraTypes
.insert(SPELL_AURA_MOD_HASTE
);
69 auraTypes
.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
73 // auraTypes contains victim auras capable of proc'ing cast auras
74 static Unit::AuraTypeSet
GenerateVictimProcCastAuraTypes()
76 static Unit::AuraTypeSet auraTypes
;
77 auraTypes
.insert(SPELL_AURA_DUMMY
);
78 auraTypes
.insert(SPELL_AURA_PRAYER_OF_MENDING
);
79 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
83 // auraTypes contains auras capable of proc effect/damage (but not cast) for attacker
84 static Unit::AuraTypeSet
GenerateAttakerProcEffectAuraTypes()
86 static Unit::AuraTypeSet auraTypes
;
87 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_DONE
);
88 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
89 auraTypes
.insert(SPELL_AURA_MOD_CASTING_SPEED
);
90 auraTypes
.insert(SPELL_AURA_MOD_RATING
);
94 // auraTypes contains auras capable of proc effect/damage (but not cast) for victim
95 static Unit::AuraTypeSet
GenerateVictimProcEffectAuraTypes()
97 static Unit::AuraTypeSet auraTypes
;
98 auraTypes
.insert(SPELL_AURA_MOD_RESISTANCE
);
99 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
100 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
101 auraTypes
.insert(SPELL_AURA_MOD_BLOCK_PERCENT
);
102 auraTypes
.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
106 static Unit::AuraTypeSet attackerProcCastAuraTypes
= GenerateAttakerProcCastAuraTypes();
107 static Unit::AuraTypeSet attackerProcEffectAuraTypes
= GenerateAttakerProcEffectAuraTypes();
109 static Unit::AuraTypeSet victimProcCastAuraTypes
= GenerateVictimProcCastAuraTypes();
110 static Unit::AuraTypeSet victimProcEffectAuraTypes
= GenerateVictimProcEffectAuraTypes();
112 // auraTypes contains auras capable of proc'ing for attacker and victim
113 static Unit::AuraTypeSet
GenerateProcAuraTypes()
115 Unit::AuraTypeSet auraTypes
;
116 auraTypes
.insert(attackerProcCastAuraTypes
.begin(),attackerProcCastAuraTypes
.end());
117 auraTypes
.insert(attackerProcEffectAuraTypes
.begin(),attackerProcEffectAuraTypes
.end());
118 auraTypes
.insert(victimProcCastAuraTypes
.begin(),victimProcCastAuraTypes
.end());
119 auraTypes
.insert(victimProcEffectAuraTypes
.begin(),victimProcEffectAuraTypes
.end());
123 static Unit::AuraTypeSet procAuraTypes
= GenerateProcAuraTypes();
125 bool IsPassiveStackableSpell( uint32 spellId
)
127 if(!IsPassiveSpell(spellId
))
130 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
134 for(int j
= 0; j
< 3; ++j
)
136 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
144 : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
146 m_objectType
|= TYPEMASK_UNIT
;
147 m_objectTypeId
= TYPEID_UNIT
;
149 m_updateFlag
= (UPDATEFLAG_LOWGUID
| UPDATEFLAG_HIGHGUID
| UPDATEFLAG_LIVING
| UPDATEFLAG_HAS_POSITION
);
151 m_attackTimer
[BASE_ATTACK
] = 0;
152 m_attackTimer
[OFF_ATTACK
] = 0;
153 m_attackTimer
[RANGED_ATTACK
] = 0;
154 m_modAttackSpeedPct
[BASE_ATTACK
] = 1.0f
;
155 m_modAttackSpeedPct
[OFF_ATTACK
] = 1.0f
;
156 m_modAttackSpeedPct
[RANGED_ATTACK
] = 1.0f
;
162 m_deathState
= ALIVE
;
164 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
165 m_currentSpells
[i
] = NULL
;
169 for(int i
= 0; i
< MAX_TOTEM
; ++i
)
172 m_ObjectSlot
[0] = m_ObjectSlot
[1] = m_ObjectSlot
[2] = m_ObjectSlot
[3] = 0;
174 //m_AurasCheck = 2000;
175 //m_removeAuraTimer = 4;
179 m_Visibility
= VISIBILITY_ON
;
181 m_detectInvisibilityMask
= 0;
182 m_invisibilityMask
= 0;
184 m_ShapeShiftFormSpellId
= 0;
185 m_canModifyStats
= false;
187 for (int i
= 0; i
< MAX_SPELL_IMMUNITY
; i
++)
188 m_spellImmune
[i
].clear();
189 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
191 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
192 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
193 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
194 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
196 // implement 50% base damage from offhand
197 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
199 for (int i
= 0; i
< 3; i
++)
201 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
202 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
204 for (int i
= 0; i
< MAX_STATS
; i
++)
205 m_createStats
[i
] = 0.0f
;
208 m_modMeleeHitChance
= 0.0f
;
209 m_modRangedHitChance
= 0.0f
;
210 m_modSpellHitChance
= 0.0f
;
211 m_baseSpellCritChance
= 5;
216 //m_victimThreat = 0.0f;
217 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
218 m_threatModifier
[i
] = 1.0f
;
220 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
221 m_speed_rate
[i
] = 1.0f
;
225 m_unit_movement_flags
= 0;
227 // remove aurastates allowing special moves
228 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
229 m_reactiveTimer
[i
] = 0;
234 // set current spells as deletable
235 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
237 if (m_currentSpells
[i
])
239 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
240 m_currentSpells
[i
] = NULL
;
244 RemoveAllGameObjects();
245 RemoveAllDynObjects();
247 if(m_charmInfo
) delete m_charmInfo
;
250 void Unit::Update( uint32 p_time
)
252 /*if(p_time > m_AurasCheck)
257 m_AurasCheck -= p_time;*/
259 // WARNING! Order of execution here is important, do not change.
260 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
261 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
262 m_Events
.Update( p_time
);
263 _UpdateSpells( p_time
);
265 // update combat timer only for players and pets
266 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
268 // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
269 // targets without stopping half way there and running off.
270 // These flags are reset after target dies or another command is given.
271 if( m_HostilRefManager
.isEmpty() )
273 // m_CombatTimer set at aura start and it will be freeze until aura removing
274 if ( m_CombatTimer
<= p_time
)
277 m_CombatTimer
-= p_time
;
281 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
283 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
286 // update abilities available only for fraction of time
287 UpdateReactives( p_time
);
289 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, GetHealth() < GetMaxHealth()*0.20f
);
290 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, GetHealth() < GetMaxHealth()*0.35f
);
292 i_motionMaster
.UpdateMotion(p_time
);
295 bool Unit::haveOffhandWeapon() const
297 if(GetTypeId() == TYPEID_PLAYER
)
298 return ((Player
*)this)->GetWeaponForAttack(OFF_ATTACK
,true);
303 void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player
* player
)
306 if(GetMotionMaster()->GetDestination(x
, y
, z
))
307 SendMonsterMoveWithSpeed(x
, y
, z
, GetUnitMovementFlags(), 0, player
);
310 void Unit::SendMonsterMoveWithSpeed(float x
, float y
, float z
, uint32 MovementFlags
, uint32 transitTime
, Player
* player
)
314 float dx
= x
- GetPositionX();
315 float dy
= y
- GetPositionY();
316 float dz
= z
- GetPositionZ();
318 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
324 double speed
= GetSpeed((MovementFlags
& MOVEMENTFLAG_WALK_MODE
) ? MOVE_WALK
: MOVE_RUN
);
328 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
330 //float orientation = (float)atan2((double)dy, (double)dx);
331 SendMonsterMove(x
, y
, z
, 0, MovementFlags
, transitTime
, player
);
334 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, uint32 MovementFlags
, uint32 Time
, Player
* player
)
336 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
337 data
.append(GetPackGUID());
339 // Point A, starting location
340 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
341 // unknown field - unrelated to orientation
342 // seems to increment about 1000 for every 1.7 seconds
343 // for now, we'll just use mstime
346 data
<< uint8(type
); // unknown
349 case 0: // normal packet
351 case 1: // stop packet
352 SendMessageToSet( &data
, true );
354 case 2: // not used currently
359 case 3: // not used currently
360 data
<< uint64(0); // probably target guid
362 case 4: // not used currently
363 data
<< float(0); // probably orientation
367 //Movement Flags (0x0 = walk, 0x100 = run, 0x200 = fly/swim)
368 data
<< uint32(MovementFlags
);
370 data
<< Time
; // Time in between points
371 data
<< uint32(1); // 1 single waypoint
372 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
375 player
->GetSession()->SendPacket(&data
);
377 SendMessageToSet( &data
, true );
380 void Unit::SendMonsterMoveByPath(Path
const& path
, uint32 start
, uint32 end
, uint32 MovementFlags
)
382 uint32 traveltime
= uint32(path
.GetTotalLength(start
, end
) * 32);
384 uint32 pathSize
= end
-start
;
386 WorldPacket
data( SMSG_MONSTER_MOVE
, (GetPackGUID().size()+4+4+4+4+1+4+4+4+pathSize
*4*3) );
387 data
.append(GetPackGUID());
388 data
<< GetPositionX();
389 data
<< GetPositionY();
390 data
<< GetPositionZ();
392 // unknown field - unrelated to orientation
393 // seems to increment about 1000 for every 1.7 seconds
394 // for now, we'll just use mstime
398 data
<< uint32( MovementFlags
);
399 data
<< uint32( traveltime
);
400 data
<< uint32( pathSize
);
401 data
.append( (char*)path
.GetNodes(start
), pathSize
* 4 * 3 );
403 //WPAssert( data.size() == 37 + pathnodes.Size( ) * 4 * 3 );
404 SendMessageToSet(&data
, true);
407 void Unit::resetAttackTimer(WeaponAttackType type
)
409 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
412 bool Unit::canReachWithAttack(Unit
*pVictim
) const
415 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
418 return IsWithinDistInMap(pVictim
, reach
);
421 void Unit::RemoveSpellsCausingAura(AuraType auraType
)
423 if (auraType
>= TOTAL_AURAS
) return;
424 AuraList::iterator iter
, next
;
425 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
432 RemoveAurasDueToSpell((*iter
)->GetId());
433 if (!m_modAuras
[auraType
].empty())
434 next
= m_modAuras
[auraType
].begin();
441 bool Unit::HasAuraType(AuraType auraType
) const
443 return (!m_modAuras
[auraType
].empty());
446 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
447 void Unit::RemoveSpellbyDamageTaken(AuraType auraType
, uint32 damage
)
449 if(!HasAuraType(auraType
))
452 // The chance to dispel an aura depends on the damage taken with respect to the casters level.
453 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
454 float chance
= float(damage
) / max_dmg
* 100.0f
;
455 if (roll_chance_f(chance
))
456 RemoveSpellsCausingAura(auraType
);
459 uint32
Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *spellProto
, bool durabilityLoss
)
461 if (!pVictim
->isAlive() || pVictim
->isInFlight() || pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
464 //You don't lose health from damage taken from another player while in a sanctuary
465 //You still see it in the combat log though
466 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
468 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
469 if(area
&& area
->flags
& AREA_FLAG_SANCTUARY
) //sanctuary
473 // remove affects from victim (including from 0 damage and DoTs)
475 pVictim
->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
477 // remove affects from attacker at any non-DoT damage (including 0 damage)
478 if( damagetype
!= DOT
)
480 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
481 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
484 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
486 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->IsStandState() && !pVictim
->hasUnitState(UNIT_STAT_STUNNED
))
487 pVictim
->SetStandState(PLAYER_STATE_NONE
);
490 //Script Event damage Deal
491 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
492 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
493 //Script Event damage taken
494 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
495 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
499 // Rage from physical damage received .
500 if(cleanDamage
&& cleanDamage
->damage
&& (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
) && pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
501 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
506 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
507 // root type spells do not dispel the root effect
508 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
509 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
511 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
513 // no xp,health if type 8 /critters/
514 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
516 pVictim
->setDeathState(JUST_DIED
);
517 pVictim
->SetHealth(0);
519 // allow loot only if has loot_id in creature_template
520 CreatureInfo
const* cInfo
= ((Creature
*)pVictim
)->GetCreatureInfo();
521 if(cInfo
&& cInfo
->lootid
)
522 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
524 // some critters required for quests
525 if(GetTypeId() == TYPEID_PLAYER
)
526 ((Player
*)this)->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
531 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
532 ((Creature
*)pVictim
)->AI()->AttackStart(this);
535 DEBUG_LOG("DealDamageStart");
537 uint32 health
= pVictim
->GetHealth();
538 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
540 // duel ends when player has 1 or less hp
541 bool duel_hasEnded
= false;
542 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
544 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
545 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
548 duel_hasEnded
= true;
551 if(pVictim
!= this && damagetype
!= DOT
)
553 SetInCombatWith(pVictim
);
554 pVictim
->SetInCombatWith(this);
556 if(Player
* attackedPlayer
= pVictim
->GetCharmerOrOwnerPlayerOrPlayerItself())
557 SetContestedPvP(attackedPlayer
);
560 // Rage from Damage made (only from direct weapon damage)
561 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
563 uint32 weaponSpeedHitFactor
;
565 switch(cleanDamage
->attackType
)
569 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
570 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
572 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
574 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
580 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
581 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
583 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
585 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
594 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& GetTypeId() == TYPEID_PLAYER
)
596 if(((Player
*)pVictim
)->InBattleGround())
598 Player
*killer
= ((Player
*)this);
599 if(killer
!= ((Player
*)pVictim
))
600 if(BattleGround
*bg
= killer
->GetBattleGround())
601 bg
->UpdatePlayerScore(killer
, SCORE_DAMAGE_DONE
, damage
);
605 if (pVictim
->GetTypeId() == TYPEID_UNIT
&& !((Creature
*)pVictim
)->isPet() && !((Creature
*)pVictim
)->hasLootRecipient())
606 ((Creature
*)pVictim
)->SetLootRecipient(this);
607 if (health
<= damage
)
609 DEBUG_LOG("DealDamage: victim just died");
611 // find player: owner of controlled `this` or `this` itself maybe
612 Player
*player
= GetCharmerOrOwnerPlayerOrPlayerItself();
614 if(pVictim
->GetTypeId() == TYPEID_UNIT
&& ((Creature
*)pVictim
)->GetLootRecipient())
615 player
= ((Creature
*)pVictim
)->GetLootRecipient();
616 // Reward player, his pets, and group/raid members
617 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
618 if(player
&& player
!=pVictim
)
619 if(player
->RewardPlayerAndGroupAtKill(pVictim
))
620 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
622 DEBUG_LOG("DealDamageAttackStop");
625 pVictim
->CombatStop();
626 pVictim
->getHostilRefManager().deleteReferences();
628 bool damageFromSpiritOfRedemtionTalent
= spellProto
&& spellProto
->Id
== 27795;
630 // if talent known but not triggered (check priest class for speedup check)
631 Aura
* spiritOfRedemtionTalentReady
= NULL
;
632 if( !damageFromSpiritOfRedemtionTalent
&& // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION
633 pVictim
->GetTypeId()==TYPEID_PLAYER
&& pVictim
->getClass()==CLASS_PRIEST
)
635 AuraList
const& vDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
636 for(AuraList::const_iterator itr
= vDummyAuras
.begin(); itr
!= vDummyAuras
.end(); ++itr
)
638 if((*itr
)->GetSpellProto()->SpellIconID
==1654)
640 spiritOfRedemtionTalentReady
= *itr
;
646 DEBUG_LOG("SET JUST_DIED");
647 if(!spiritOfRedemtionTalentReady
)
648 pVictim
->setDeathState(JUST_DIED
);
650 DEBUG_LOG("DealDamageHealth1");
652 if(spiritOfRedemtionTalentReady
)
654 // save value before aura remove
655 uint32 ressSpellId
= pVictim
->GetUInt32Value(PLAYER_SELF_RES_SPELL
);
657 ressSpellId
= ((Player
*)pVictim
)->GetResurrectionSpellId();
659 //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
660 pVictim
->RemoveAllAurasOnDeath();
662 // restore for use at real death
663 pVictim
->SetUInt32Value(PLAYER_SELF_RES_SPELL
,ressSpellId
);
665 // FORM_SPIRITOFREDEMPTION and related auras
666 pVictim
->CastSpell(pVictim
,27827,true,NULL
,spiritOfRedemtionTalentReady
);
669 pVictim
->SetHealth(0);
671 // remember victim PvP death for corpse type and corpse reclaim delay
672 // at original death (not at SpiritOfRedemtionTalent timeout)
673 if( pVictim
->GetTypeId()==TYPEID_PLAYER
&& !damageFromSpiritOfRedemtionTalent
)
674 ((Player
*)pVictim
)->SetPvPDeath(player
!=NULL
);
676 // Call KilledUnit for creatures
677 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
678 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
681 if ( pVictim
->GetTypeId() == TYPEID_PLAYER
)
683 if(GetTypeId() == TYPEID_UNIT
)
684 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
, GetEntry());
685 else if(GetTypeId() == TYPEID_PLAYER
)
686 ((Player
*)pVictim
)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
, 1);
689 // 10% durability loss on death
690 // clean InHateListOf
691 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
693 // only if not player and not controlled by player pet. And not at BG
694 if (durabilityLoss
&& !player
&& !((Player
*)pVictim
)->InBattleGround())
696 DEBUG_LOG("We are dead, loosing 10 percents durability");
697 ((Player
*)pVictim
)->DurabilityLossAll(0.10f
,false);
698 // durability lost message
699 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
700 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
703 else // creature died
705 DEBUG_LOG("DealDamageNotPlayer");
706 Creature
*cVictim
= (Creature
*)pVictim
;
708 if(!cVictim
->isPet())
710 cVictim
->DeleteThreatList();
711 cVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
713 // Call creature just died function
715 cVictim
->AI()->JustDied(this);
717 // Dungeon specific stuff, only applies to players killing creatures
718 if(cVictim
->GetInstanceId())
720 Map
*m
= cVictim
->GetMap();
721 Player
*creditedPlayer
= GetCharmerOrOwnerPlayerOrPlayerItself();
722 // TODO: do instance binding anyway if the charmer/owner is offline
724 if(m
->IsDungeon() && creditedPlayer
)
726 if(m
->IsRaid() || m
->IsHeroic())
728 if(cVictim
->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_INSTANCE_BIND
)
729 ((InstanceMap
*)m
)->PermBindAllPlayers(creditedPlayer
);
733 // the reset time is set but not added to the scheduler
734 // until the players leave the instance
735 time_t resettime
= cVictim
->GetRespawnTimeEx() + 2 * HOUR
;
736 if(InstanceSave
*save
= sInstanceSaveManager
.GetInstanceSave(cVictim
->GetInstanceId()))
737 if(save
->GetResetTime() < resettime
) save
->SetResetTime(resettime
);
743 // last damage from non duel opponent or opponent controlled creature
746 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
747 Player
*he
= (Player
*)pVictim
;
751 he
->duel
->opponent
->CombatStopWithPets(true);
752 he
->CombatStopWithPets(true);
754 he
->DuelComplete(DUEL_INTERUPTED
);
757 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
758 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->InBattleGround())
760 Player
*killed
= ((Player
*)pVictim
);
761 if(BattleGround
*bg
= killed
->GetBattleGround())
763 bg
->HandleKillPlayer(killed
, player
);
764 //later we can add support for creature->player kills here i'm
765 //not sure, but i guess those kills also get counted in av
766 //else if(GetTypeId() == TYPEID_UNIT)
767 // bg->HandleKillPlayer(killed,(Creature*)this);
770 else // if (health <= damage)
772 DEBUG_LOG("DealDamageAlive");
774 pVictim
->ModifyHealth(- (int32
)damage
);
776 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
777 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
779 uint32 procVictim
= PROC_FLAG_NONE
;
781 // if just dropped below 20% (for CheatDeath)
782 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
783 procVictim
= PROC_FLAG_LOW_HEALTH
;
785 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
788 if(damagetype
!= DOT
)
792 // if have target and damage pVictim just call AI reaction
793 if(pVictim
!= getVictim() && pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI())
794 ((Creature
*)pVictim
)->AI()->AttackedBy(this);
798 // if not have main target then attack state with target (including AI call)
799 //start melee attacks only after melee hit
800 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
804 // polymorphed and other negative transformed cases
805 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
806 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
808 if(damagetype
== DIRECT_DAMAGE
|| damagetype
== SPELL_DIRECT_DAMAGE
)
809 pVictim
->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
);
811 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
813 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
814 pVictim
->AddThreat(this, damage
*2, damageSchoolMask
, spellProto
);
816 pVictim
->AddThreat(this, damage
, damageSchoolMask
, spellProto
);
818 else // victim is a player
820 // Rage from damage received
821 if(this != pVictim
&& pVictim
->getPowerType() == POWER_RAGE
)
823 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
824 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
827 // random durability for items (HIT TAKEN)
828 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
830 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
831 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(slot
);
835 if(GetTypeId()==TYPEID_PLAYER
)
837 // random durability for items (HIT DONE)
838 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_DAMAGE
)))
840 EquipmentSlots slot
= EquipmentSlots(urand(0,EQUIPMENT_SLOT_END
-1));
841 ((Player
*)this)->DurabilityPointLossForEquipSlot(slot
);
845 // TODO: Store auras by interrupt flag to speed this up.
846 AuraMap
& vAuras
= pVictim
->GetAuras();
847 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
849 const SpellEntry
*se
= i
->second
->GetSpellProto();
851 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
854 if (se
->procFlags
& (1<<3))
856 if (!roll_chance_i(se
->procChance
))
861 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
862 // FIXME: this may cause the auras with proc chance to be rerolled several times
863 next
= vAuras
.begin();
868 if (damagetype
!= NODAMAGE
&& damage
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
870 if( damagetype
!= DOT
)
872 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
874 // skip channeled spell (processed differently below)
875 if (i
== CURRENT_CHANNELED_SPELL
)
878 if(Spell
* spell
= pVictim
->m_currentSpells
[i
])
879 if(spell
->getState() == SPELL_STATE_PREPARING
)
884 if(Spell
* spell
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
886 if (spell
->getState() == SPELL_STATE_CASTING
)
888 uint32 channelInterruptFlags
= spell
->m_spellInfo
->ChannelInterruptFlags
;
889 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
891 if(pVictim
!=this) //don't shorten the duration of channeling if you damage yourself
892 spell
->DelayedChannel();
894 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
896 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
897 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
900 else if (spell
->getState() == SPELL_STATE_DELAYED
)
901 // break channeled spell in delayed state on damage
903 sLog
.outDetail("Spell %u canceled at damage!",spell
->m_spellInfo
->Id
);
904 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
909 // last damage from duel opponent
912 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
913 Player
*he
= (Player
*)pVictim
;
919 he
->duel
->opponent
->CombatStopWithPets(true);
920 he
->CombatStopWithPets(true);
922 he
->CastSpell(he
, 7267, true); // beg
923 he
->DuelComplete(DUEL_WON
);
927 DEBUG_LOG("DealDamageEnd returned %d damage", damage
);
932 void Unit::CastStop(uint32 except_spellid
)
934 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
935 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
!=except_spellid
)
936 InterruptSpell(i
,false);
939 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
941 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
945 sLog
.outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId
,(GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
949 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
952 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
956 sLog
.outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
961 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
963 if(!originalCaster
&& triggeredByAura
)
964 originalCaster
= triggeredByAura
->GetCasterGUID();
966 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
968 SpellCastTargets targets
;
969 targets
.setUnitTarget( Victim
);
970 spell
->m_CastItem
= castItem
;
971 spell
->prepare(&targets
, triggeredByAura
);
974 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
976 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
980 sLog
.outError("CastCustomSpell: unknown spell id %i\n", spellId
);
984 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggeredByAura
, originalCaster
);
987 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
)
991 sLog
.outError("CastCustomSpell: unknown spell");
996 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
998 if(!originalCaster
&& triggeredByAura
)
999 originalCaster
= triggeredByAura
->GetCasterGUID();
1001 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1004 spell
->m_currentBasePoints
[0] = *bp0
-int32(spellInfo
->EffectBaseDice
[0]);
1007 spell
->m_currentBasePoints
[1] = *bp1
-int32(spellInfo
->EffectBaseDice
[1]);
1010 spell
->m_currentBasePoints
[2] = *bp2
-int32(spellInfo
->EffectBaseDice
[2]);
1012 SpellCastTargets targets
;
1013 targets
.setUnitTarget( Victim
);
1014 spell
->m_CastItem
= castItem
;
1015 spell
->prepare(&targets
, triggeredByAura
);
1018 // used for scripting
1019 void Unit::CastSpell(float x
, float y
, float z
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1021 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
1025 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()));
1029 CastSpell(x
, y
, z
,spellInfo
,triggered
,castItem
,triggeredByAura
, originalCaster
);
1032 // used for scripting
1033 void Unit::CastSpell(float x
, float y
, float z
, SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggeredByAura
, uint64 originalCaster
)
1037 sLog
.outError("CastSpell(x,y,z): unknown spell by caster: %s %u)", (GetTypeId()==TYPEID_PLAYER
? "player (GUID:" : "creature (Entry:"),(GetTypeId()==TYPEID_PLAYER
? GetGUIDLow() : GetEntry()));
1042 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
1044 if(!originalCaster
&& triggeredByAura
)
1045 originalCaster
= triggeredByAura
->GetCasterGUID();
1047 Spell
*spell
= new Spell(this, spellInfo
, triggered
, originalCaster
);
1049 SpellCastTargets targets
;
1050 targets
.setDestination(x
, y
, z
);
1051 spell
->m_CastItem
= castItem
;
1052 spell
->prepare(&targets
, triggeredByAura
);
1055 void Unit::DealFlatDamage(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
1057 // TODO this in only generic way, check for exceptions
1058 DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage
);
1060 // Per-damage class calculation
1061 switch (spellInfo
->DmgClass
)
1063 // Melee and Ranged Spells
1064 case SPELL_DAMAGE_CLASS_RANGED
:
1065 case SPELL_DAMAGE_CLASS_MELEE
:
1067 // Calculate physical outcome
1068 MeleeHitOutcome outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
1070 //Used to store the Hit Outcome
1071 cleanDamage
->hitOutCome
= outcome
;
1073 // Return miss/evade first (sends miss message)
1076 case MELEE_HIT_EVADE
:
1078 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_EVADES
,0);
1082 case MELEE_HIT_MISS
:
1084 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), 0, 0,0,VICTIMSTATE_NORMAL
,0);
1087 if(GetTypeId()== TYPEID_PLAYER
)
1088 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
1090 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
1095 // Hitinfo, Victimstate
1096 uint32 hitInfo
= HITINFO_NORMALSWING
;
1097 VictimState victimState
= VICTIMSTATE_NORMAL
;
1100 if ( GetSpellSchoolMask(spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
)
1102 // apply spellmod to Done damage
1103 if(Player
* modOwner
= GetSpellModOwner())
1104 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_DAMAGE
, *damage
);
1106 //Calculate armor mitigation
1107 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1109 // random durability for main hand weapon (ABSORB)
1110 if(damageAfterArmor
< *damage
)
1111 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1112 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1113 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1115 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1116 *damage
= damageAfterArmor
;
1121 // Calculate damage bonus
1122 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1128 case MELEE_HIT_BLOCK_CRIT
:
1129 case MELEE_HIT_CRIT
:
1131 uint32 bonusDmg
= *damage
;
1133 // Apply crit_damage bonus
1134 if(Player
* modOwner
= GetSpellModOwner())
1135 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, bonusDmg
);
1137 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1138 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1139 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1140 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1141 bonusDmg
= uint32(bonusDmg
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1143 *damage
+= bonusDmg
;
1145 // Resilience - reduce crit damage
1146 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1148 uint32 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1149 cleanDamage
->damage
+= resilienceReduction
;
1150 *damage
-= resilienceReduction
;
1154 hitInfo
|= HITINFO_CRITICALHIT
;
1156 ModifyAuraState(AURA_STATE_CRIT
, true);
1157 StartReactiveTimer( REACTIVE_CRIT
);
1159 if(getClass()==CLASS_HUNTER
)
1161 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1162 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1165 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1167 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1168 if (blocked_amount
>= *damage
)
1170 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1171 victimState
= VICTIMSTATE_BLOCKS
;
1172 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1177 // To Help Calculate Rage
1178 cleanDamage
->damage
+= blocked_amount
;
1179 *damage
= *damage
- blocked_amount
;
1182 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1183 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1185 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1188 ((Player
*)pVictim
)->UpdateDefense();
1190 // random durability for main hand weapon (BLOCK)
1191 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1192 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1197 case MELEE_HIT_PARRY
:
1199 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1201 victimState
= VICTIMSTATE_PARRY
;
1203 // Counter-attack ( explained in Unit::DoAttackDamage() )
1204 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
) )
1206 // Get attack timers
1207 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1208 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1210 // Reduce attack time
1211 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1213 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1214 float percent60
= 3 * percent20
;
1215 if(offtime
> percent20
&& offtime
<= percent60
)
1217 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1219 else if(offtime
> percent60
)
1221 offtime
-= 2 * percent20
;
1222 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1227 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1228 float percent60
= 3 * percent20
;
1229 if(basetime
> percent20
&& basetime
<= percent60
)
1231 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1233 else if(basetime
> percent60
)
1235 basetime
-= 2 * percent20
;
1236 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1241 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1243 // Update victim defense ?
1244 ((Player
*)pVictim
)->UpdateDefense();
1246 // random durability for main hand weapon (PARRY)
1247 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1248 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1252 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1254 // Mongoose bite - set only Counterattack here
1255 if (pVictim
->getClass() == CLASS_HUNTER
)
1257 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1258 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1262 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1263 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1267 case MELEE_HIT_DODGE
:
1269 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1270 ((Player
*)pVictim
)->UpdateDefense();
1272 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1274 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1275 victimState
= VICTIMSTATE_DODGE
;
1278 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1281 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
1283 ((Player
*)this)->AddComboPoints(pVictim
, 1);
1284 StartReactiveTimer( REACTIVE_OVERPOWER
);
1288 if (pVictim
->getClass() != CLASS_ROGUE
)
1290 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1291 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1295 case MELEE_HIT_BLOCK
:
1297 uint32 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1298 if (blocked_amount
>= *damage
)
1300 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1301 victimState
= VICTIMSTATE_BLOCKS
;
1302 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1307 // To Help Calculate Rage
1308 cleanDamage
->damage
+= blocked_amount
;
1309 *damage
= *damage
- blocked_amount
;
1312 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1313 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1315 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1318 ((Player
*)pVictim
)->UpdateDefense();
1320 // random durability for main hand weapon (BLOCK)
1321 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1322 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1326 case MELEE_HIT_EVADE
: // already processed early
1327 case MELEE_HIT_MISS
: // already processed early
1328 case MELEE_HIT_GLANCING
:
1329 case MELEE_HIT_CRUSHING
:
1330 case MELEE_HIT_NORMAL
:
1334 // do all damage=0 cases here
1336 CastMeleeProcDamageAndSpell(pVictim
,0,GetSpellSchoolMask(spellInfo
),BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1341 case SPELL_DAMAGE_CLASS_NONE
:
1342 case SPELL_DAMAGE_CLASS_MAGIC
:
1344 // Calculate damage bonus
1345 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1347 *crit
= isSpellCrit(pVictim
, spellInfo
, GetSpellSchoolMask(spellInfo
), BASE_ATTACK
);
1350 *damage
= SpellCriticalBonus(spellInfo
, *damage
, pVictim
);
1352 // Resilience - reduce crit damage
1353 if (pVictim
&& pVictim
->GetTypeId()==TYPEID_PLAYER
)
1355 uint32 damage_reduction
= ((Player
*)pVictim
)->GetSpellCritDamageReduction(*damage
);
1356 if(*damage
> damage_reduction
)
1357 *damage
-= damage_reduction
;
1362 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1364 // spell proc all magic damage==0 case in this function
1368 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1369 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1371 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1378 // TODO this in only generic way, check for exceptions
1379 DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage
);
1382 uint32
Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1384 if(!this || !pVictim
)
1386 if(!isAlive() || !pVictim
->isAlive())
1389 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1393 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1397 DealFlatDamage(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1399 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage)
1402 // Calculate absorb & resists
1406 CalcAbsorbResist(pVictim
,GetSpellSchoolMask(spellInfo
), SPELL_DIRECT_DAMAGE
, damage
, &absorb
, &resist
);
1408 //No more damage left, target absorbed and/or resisted all damage
1409 if (damage
> absorb
+ resist
)
1410 damage
-= absorb
+ resist
; //Remove Absorbed and Resisted from damage actually dealt
1413 uint32 HitInfo
= HITINFO_SWINGNOHITSOUND
;
1416 HitInfo
|= HITINFO_ABSORB
;
1419 HitInfo
|= HITINFO_RESIST
;
1420 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, GetSpellSchoolMask(spellInfo
), spellInfo
,isTriggeredSpell
);
1424 SendAttackStateUpdate(HitInfo
, pVictim
, 1, GetSpellSchoolMask(spellInfo
), damage
, absorb
,resist
,VICTIMSTATE_NORMAL
,0);
1429 damage
= DealDamage(pVictim
, damage
, &cleanDamage
, SPELL_DIRECT_DAMAGE
, GetSpellSchoolMask(spellInfo
), spellInfo
, true);
1432 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1433 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1435 // Actual log sent to client
1436 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, GetSpellSchoolMask(spellInfo
), absorb
, resist
, false, 0, crit
);
1439 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1440 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1444 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1445 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1448 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, GetSpellSchoolMask(spellInfo
), spellInfo
, isTriggeredSpell
);
1454 // all spell proc for 0 normal and magic damage called in DealFlatDamage
1457 if(cleanDamage
.damage
)
1458 // Rage from damage received.
1459 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1460 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1466 void Unit::HandleEmoteCommand(uint32 anim_id
)
1468 WorldPacket
data( SMSG_EMOTE
, 12 );
1469 data
<< uint32(anim_id
);
1470 data
<< uint64(GetGUID());
1471 SendMessageToSet(&data
, true);
1474 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1476 uint32 newdamage
= 0;
1477 float armor
= pVictim
->GetArmor();
1478 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1479 armor
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, SPELL_SCHOOL_MASK_NORMAL
);
1481 if (armor
<0.0f
) armor
=0.0f
;
1483 float tmpvalue
= 0.0f
;
1484 if(getLevel() <= 59) //Level 1-59
1485 tmpvalue
= armor
/ (armor
+ 400.0f
+ 85.0f
* getLevel());
1486 else if(getLevel() < 70) //Level 60-69
1487 tmpvalue
= armor
/ (armor
- 22167.5f
+ 467.5f
* getLevel());
1489 tmpvalue
= armor
/ (armor
+ 10557.5f
);
1493 if(tmpvalue
> 0.75f
)
1495 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1497 return (newdamage
> 1) ? newdamage
: 1;
1500 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchoolMask schoolMask
, DamageEffectType damagetype
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1502 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1505 // Magic damage, check for resists
1506 if ((schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)==0)
1508 // Get base victim resistance for school
1509 float tmpvalue2
= (float)pVictim
->GetResistance(GetFirstSchoolInMask(schoolMask
));
1510 // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura
1511 tmpvalue2
+= (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE
, schoolMask
);
1513 tmpvalue2
*= (float)(0.15f
/ getLevel());
1514 if (tmpvalue2
< 0.0f
)
1516 if (tmpvalue2
> 0.75f
)
1518 uint32 ran
= urand(0, 100);
1519 uint32 faq
[4] = {24,6,4,6};
1522 for (uint8 i
= 0; i
< 4; i
++)
1524 Binom
+= 2400 *( powf(tmpvalue2
, i
) * powf( (1-tmpvalue2
), (4-i
)))/faq
[i
];
1530 if (damagetype
== DOT
&& m
== 4)
1531 *resist
+= uint32(damage
- 1);
1533 *resist
+= uint32(damage
* m
/ 4);
1534 if(*resist
> damage
)
1540 int32 RemainingDamage
= damage
- *resist
;
1542 // absorb without mana cost
1543 int32 reflectDamage
= 0;
1544 Aura
* reflectAura
= NULL
;
1545 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1546 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
> 0; i
= next
)
1550 if (((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1554 if((*i
)->GetSpellProto()->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (*i
)->GetSpellProto()->SpellIconID
== 2109)
1556 if (((Player
*)pVictim
)->HasSpellCooldown(31231))
1558 if (pVictim
->GetHealth() <= RemainingDamage
)
1560 int32 chance
= (*i
)->GetModifier()->m_amount
;
1561 if (roll_chance_i(chance
))
1563 pVictim
->CastSpell(pVictim
,31231,true);
1564 ((Player
*)pVictim
)->AddSpellCooldown(31231,0,time(NULL
)+60);
1566 // with health > 10% lost health until health==10%, in other case no losses
1567 uint32 health10
= pVictim
->GetMaxHealth()/10;
1568 RemainingDamage
= pVictim
->GetHealth() > health10
? pVictim
->GetHealth() - health10
: 0;
1574 int32 currentAbsorb
;
1577 if ((pVictim
!= this) && (*i
)->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_PRIEST
&& (*i
)->GetSpellProto()->SpellFamilyFlags
== 0x1)
1579 if(Unit
* caster
= (*i
)->GetCaster())
1581 AuraList
const& vOverRideCS
= caster
->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
1582 for(AuraList::const_iterator k
= vOverRideCS
.begin(); k
!= vOverRideCS
.end(); ++k
)
1584 switch((*k
)->GetModifier()->m_miscvalue
)
1586 case 5065: // Rank 1
1587 case 5064: // Rank 2
1588 case 5063: // Rank 3
1589 case 5062: // Rank 4
1590 case 5061: // Rank 5
1592 if(RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1593 reflectDamage
= (*i
)->GetModifier()->m_amount
* (*k
)->GetModifier()->m_amount
/100;
1595 reflectDamage
= (*k
)->GetModifier()->m_amount
* RemainingDamage
/100;
1608 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1610 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1611 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1612 next
= vSchoolAbsorb
.begin();
1616 currentAbsorb
= RemainingDamage
;
1617 (*i
)->GetModifier()->m_amount
-= RemainingDamage
;
1620 RemainingDamage
-= currentAbsorb
;
1622 // do not cast spells while looping auras; auras can get invalid otherwise
1624 pVictim
->CastCustomSpell(this, 33619, &reflectDamage
, NULL
, NULL
, true, NULL
, reflectAura
);
1626 // absorb by mana cost
1627 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1628 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
> 0; i
= next
)
1632 // check damage school mask
1633 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1636 int32 currentAbsorb
;
1637 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1638 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1640 currentAbsorb
= RemainingDamage
;
1642 float manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1643 if(Player
*modOwner
= GetSpellModOwner())
1644 modOwner
->ApplySpellMod((*i
)->GetId(), SPELLMOD_MULTIPLE_VALUE
, manaMultiplier
);
1646 int32 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1647 if (currentAbsorb
> maxAbsorb
)
1648 currentAbsorb
= maxAbsorb
;
1650 (*i
)->GetModifier()->m_amount
-= currentAbsorb
;
1651 if((*i
)->GetModifier()->m_amount
<= 0)
1653 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1654 next
= vManaShield
.begin();
1657 int32 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1658 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1660 RemainingDamage
-= currentAbsorb
;
1663 // only split damage if not damaging yourself
1666 AuraList
const& vSplitDamageFlat
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_FLAT
);
1667 for(AuraList::const_iterator i
= vSplitDamageFlat
.begin(), next
; i
!= vSplitDamageFlat
.end() && RemainingDamage
>= 0; i
= next
)
1671 // check damage school mask
1672 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1675 // Damage can be splitted only if aura has an alive caster
1676 Unit
*caster
= (*i
)->GetCaster();
1677 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1680 int32 currentAbsorb
;
1681 if (RemainingDamage
>= (*i
)->GetModifier()->m_amount
)
1682 currentAbsorb
= (*i
)->GetModifier()->m_amount
;
1684 currentAbsorb
= RemainingDamage
;
1686 RemainingDamage
-= currentAbsorb
;
1688 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, currentAbsorb
, schoolMask
, 0, 0, false, 0, false);
1690 CleanDamage cleanDamage
= CleanDamage(currentAbsorb
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1691 DealDamage(caster
, currentAbsorb
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1694 AuraList
const& vSplitDamagePct
= pVictim
->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT
);
1695 for(AuraList::const_iterator i
= vSplitDamagePct
.begin(), next
; i
!= vSplitDamagePct
.end() && RemainingDamage
>= 0; i
= next
)
1699 // check damage school mask
1700 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
)==0)
1703 // Damage can be splitted only if aura has an alive caster
1704 Unit
*caster
= (*i
)->GetCaster();
1705 if(!caster
|| caster
== pVictim
|| !caster
->IsInWorld() || !caster
->isAlive())
1708 int32 splitted
= int32(RemainingDamage
* (*i
)->GetModifier()->m_amount
/ 100.0f
);
1710 RemainingDamage
-= splitted
;
1712 SendSpellNonMeleeDamageLog(caster
, (*i
)->GetSpellProto()->Id
, splitted
, schoolMask
, 0, 0, false, 0, false);
1714 CleanDamage cleanDamage
= CleanDamage(splitted
, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1715 DealDamage(caster
, splitted
, &cleanDamage
, DIRECT_DAMAGE
, schoolMask
, (*i
)->GetSpellProto(), false);
1719 *absorb
= damage
- RemainingDamage
- *resist
;
1722 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
)
1724 MeleeHitOutcome outcome
;
1726 // If is casted Melee spell, calculate like physical
1728 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1730 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1732 if(outcome
== MELEE_HIT_MISS
||outcome
== MELEE_HIT_DODGE
||outcome
== MELEE_HIT_BLOCK
||outcome
== MELEE_HIT_PARRY
)
1733 pVictim
->AddThreat(this, 0.0f
);
1736 case MELEE_HIT_EVADE
:
1738 *hitInfo
|= HITINFO_MISS
;
1740 cleanDamage
->damage
= 0;
1743 case MELEE_HIT_MISS
:
1745 *hitInfo
|= HITINFO_MISS
;
1747 cleanDamage
->damage
= 0;
1748 if(GetTypeId()== TYPEID_PLAYER
)
1749 ((Player
*)this)->UpdateWeaponSkill(attType
);
1754 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1755 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1756 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1758 // -probability is between 0% and 40%
1760 float Probability
= 20;
1762 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1763 if( pVictim
->getLevel() < 30 )
1764 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1766 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue(this);
1767 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill(pVictim
);
1769 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1771 if(Probability
> 40.0f
)
1772 Probability
= 40.0f
;
1774 if(roll_chance_f(Probability
))
1775 CastSpell(pVictim
, 1604, true);
1778 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1779 if (damageSchoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
1781 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1783 // random durability for main hand weapon (ABSORB)
1784 if(damageAfterArmor
< *damage
)
1785 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1786 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_ABSORB
)))
1787 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START
,EQUIPMENT_SLOT_BACK
)));
1789 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1790 *damage
= damageAfterArmor
;
1793 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1794 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1796 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1797 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1801 case MELEE_HIT_BLOCK_CRIT
:
1802 case MELEE_HIT_CRIT
:
1804 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| HITINFO_UNK2
;
1808 crit_bonus
= *damage
;
1810 // Apply crit_damage bonus for melee spells
1813 if(Player
* modOwner
= GetSpellModOwner())
1814 modOwner
->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1816 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
1817 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
);
1818 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
1819 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
1820 crit_bonus
= uint32(crit_bonus
* ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
);
1823 *damage
+= crit_bonus
;
1825 uint32 resilienceReduction
= 0;
1827 if(attType
== RANGED_ATTACK
)
1829 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
);
1830 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1831 // Resilience - reduce crit damage
1832 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1833 resilienceReduction
= ((Player
*)pVictim
)->GetRangedCritDamageReduction(*damage
);
1837 int32 mod
= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
);
1838 mod
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
);
1839 *damage
= int32((*damage
) * float((100.0f
+ mod
)/100.0f
));
1840 // Resilience - reduce crit damage
1841 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
1842 resilienceReduction
= ((Player
*)pVictim
)->GetMeleeCritDamageReduction(*damage
);
1845 *damage
-= resilienceReduction
;
1846 cleanDamage
->damage
+= resilienceReduction
;
1848 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1849 ((Player
*)this)->UpdateWeaponSkill(attType
);
1851 ModifyAuraState(AURA_STATE_CRIT
, true);
1852 StartReactiveTimer( REACTIVE_CRIT
);
1854 if(getClass()==CLASS_HUNTER
)
1856 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, true);
1857 StartReactiveTimer( REACTIVE_HUNTER_CRIT
);
1860 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
1862 *blocked_amount
= pVictim
->GetShieldBlockValue();
1864 if (pVictim
->GetUnitBlockChance())
1865 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1867 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1869 //Only set VICTIMSTATE_BLOCK on a full block
1870 if (*blocked_amount
>= uint32(*damage
))
1872 *victimState
= VICTIMSTATE_BLOCKS
;
1873 *blocked_amount
= uint32(*damage
);
1876 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1879 ((Player
*)pVictim
)->UpdateDefense();
1881 // random durability for main hand weapon (BLOCK)
1882 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
1883 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
1886 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1887 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1891 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1894 case MELEE_HIT_PARRY
:
1896 if(attType
== RANGED_ATTACK
) //range attack - no parry
1898 outcome
= MELEE_HIT_NORMAL
;
1902 cleanDamage
->damage
+= *damage
;
1904 *victimState
= VICTIMSTATE_PARRY
;
1906 // instant (maybe with small delay) counter attack
1908 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1909 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1911 // after parry nearest next attack time will reduced at %40 from full attack time.
1912 // The delay cannot be reduced to less than 20% of your weapon base swing delay.
1913 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1915 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1916 float percent60
= 3*percent20
;
1917 // set to 20% if in range 20%...20+40% of full time
1918 if(offtime
> percent20
&& offtime
<= percent60
)
1920 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1922 // decrease at %40 from full time
1923 else if(offtime
> percent60
)
1925 offtime
-= 2*percent20
;
1926 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1932 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1933 float percent60
= 3*percent20
;
1934 // set to 20% if in range 20%...20+40% of full time
1935 if(basetime
> percent20
&& basetime
<= percent60
)
1937 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1939 // decrease at %40 from full time
1940 else if(basetime
> percent60
)
1942 basetime
-= 2*percent20
;
1943 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1949 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1951 // Update victim defense ?
1952 ((Player
*)pVictim
)->UpdateDefense();
1954 // random durability for main hand weapon (PARRY)
1955 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_PARRY
)))
1956 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND
);
1959 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1961 if (pVictim
->getClass() == CLASS_HUNTER
)
1963 pVictim
->ModifyAuraState(AURA_STATE_HUNTER_PARRY
,true);
1964 pVictim
->StartReactiveTimer( REACTIVE_HUNTER_PARRY
);
1968 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1969 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1972 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1975 case MELEE_HIT_DODGE
:
1977 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1979 outcome
= MELEE_HIT_NORMAL
;
1983 cleanDamage
->damage
+= *damage
;
1985 *victimState
= VICTIMSTATE_DODGE
;
1987 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1988 ((Player
*)pVictim
)->UpdateDefense();
1990 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1992 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1994 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1995 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
1999 if (GetTypeId() == TYPEID_PLAYER
&& getClass() == CLASS_WARRIOR
)
2001 ((Player
*)this)->AddComboPoints(pVictim
, 1);
2002 StartReactiveTimer( REACTIVE_OVERPOWER
);
2005 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2008 case MELEE_HIT_BLOCK
:
2010 *blocked_amount
= pVictim
->GetShieldBlockValue();
2012 if (pVictim
->GetUnitBlockChance())
2013 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
2015 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
2017 //Only set VICTIMSTATE_BLOCK on a full block
2018 if (*blocked_amount
>= uint32(*damage
))
2020 *victimState
= VICTIMSTATE_BLOCKS
;
2021 *blocked_amount
= uint32(*damage
);
2024 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
2027 ((Player
*)pVictim
)->UpdateDefense();
2029 // random durability for main hand weapon (BLOCK)
2030 if (roll_chance_f(sWorld
.getRate(RATE_DURABILITY_LOSS_BLOCK
)))
2031 ((Player
*)pVictim
)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND
);
2034 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
2035 pVictim
->StartReactiveTimer( REACTIVE_DEFENSE
);
2039 case MELEE_HIT_GLANCING
:
2041 float reducePercent
= 1.0f
; //damage factor
2043 // calculate base values and mods
2044 float baseLowEnd
= 1.3;
2045 float baseHighEnd
= 1.2;
2046 switch(getClass()) // lowering base values for casters
2058 float maxLowEnd
= 0.6;
2059 switch(getClass()) // upper for melee classes
2063 case CLASS_DEATH_KNIGHT
:
2064 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
2068 int32 diff
= int32(pVictim
->GetDefenseSkillValue(this)) - int32(GetWeaponSkillValue(attType
,pVictim
));
2069 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
2070 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
2072 // apply max/min bounds
2073 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
2075 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
2078 if ( highEnd
< 0.2f
) //high end limits
2080 if ( highEnd
> 0.99f
)
2083 if(lowEnd
> highEnd
) // prevent negative range size
2086 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
2088 *damage
= uint32(reducePercent
* *damage
);
2089 cleanDamage
->damage
+= *damage
;
2090 *hitInfo
|= HITINFO_GLANCING
;
2093 case MELEE_HIT_CRUSHING
:
2095 // 150% normal damage
2096 *damage
+= (*damage
/ 2);
2097 cleanDamage
->damage
= *damage
;
2098 *hitInfo
|= HITINFO_CRUSHING
;
2099 // TODO: victimState, victim animation?
2106 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
2107 if(*victimState
!= VICTIMSTATE_BLOCKS
)
2109 MeleeDamageBonus(pVictim
, damage
,attType
,spellCasted
);
2110 CalcAbsorbResist(pVictim
, damageSchoolMask
, DIRECT_DAMAGE
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
2113 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
2114 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
2116 cleanDamage
->damage
+= *blocked_amount
;
2118 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
2120 //*hitInfo = 0x00010020;
2121 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
2123 CastMeleeProcDamageAndSpell(pVictim
, 0, damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2127 // update at damage Judgement aura duration that applied by attacker at victim
2130 AuraMap
const& vAuras
= pVictim
->GetAuras();
2131 for(AuraMap::const_iterator itr
= vAuras
.begin(); itr
!= vAuras
.end(); ++itr
)
2133 SpellEntry
const *spellInfo
= (*itr
).second
->GetSpellProto();
2134 if( (spellInfo
->AttributesEx3
& 0x40000) && spellInfo
->SpellFamilyName
== SPELLFAMILY_PALADIN
&&
2135 ((*itr
).second
->GetCasterGUID() == GetGUID() && (!spellCasted
|| spellCasted
->Id
== 35395)) )
2137 (*itr
).second
->SetAuraDuration((*itr
).second
->GetAuraMaxDuration());
2138 (*itr
).second
->SendAuraUpdate(false);
2143 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), damageSchoolMask
, attType
, outcome
, spellCasted
, isTriggeredSpell
);
2145 // victim's damage shield
2146 // yet another hack to fix crashes related to the aura getting removed during iteration
2147 std::set
<Aura
*> alreadyDone
;
2148 uint32 removedAuras
= pVictim
->m_removedAuras
;
2149 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
2150 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
2153 if (alreadyDone
.find(*i
) == alreadyDone
.end())
2155 alreadyDone
.insert(*i
);
2156 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
2157 if (pVictim
->m_removedAuras
> removedAuras
)
2159 removedAuras
= pVictim
->m_removedAuras
;
2160 next
= vDamageShields
.begin();
2166 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool extra
)
2168 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNNED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
2171 if (!pVictim
->isAlive())
2174 if(IsNonMeleeSpellCasted(false))
2178 if (attType
== BASE_ATTACK
)
2179 hitInfo
= HITINFO_NORMALSWING2
;
2180 else if (attType
== OFF_ATTACK
)
2181 hitInfo
= HITINFO_LEFTSWING
;
2183 return; // ignore ranged case
2185 uint32 extraAttacks
= m_extraAttacks
;
2187 // melee attack spell casted at main hand attack only
2188 if (attType
== BASE_ATTACK
&& m_currentSpells
[CURRENT_MELEE_SPELL
])
2190 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
2192 // not recent extra attack only at any non extra attack (melee spell case)
2193 if(!extra
&& extraAttacks
)
2195 while(m_extraAttacks
)
2197 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2198 if(m_extraAttacks
> 0)
2206 VictimState victimState
= VICTIMSTATE_NORMAL
;
2208 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
2209 uint32 blocked_dmg
= 0;
2210 uint32 absorbed_dmg
= 0;
2211 uint32 resisted_dmg
= 0;
2213 SpellSchoolMask meleeSchoolMask
= GetMeleeDamageSchoolMask();
2215 if(pVictim
->IsImmunedToDamage(meleeSchoolMask
,true)) // use charges
2217 SendAttackStateUpdate (HITINFO_NORMALSWING
, pVictim
, 1, meleeSchoolMask
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
2219 // not recent extra attack only at any non extra attack (miss case)
2220 if(!extra
&& extraAttacks
)
2222 while(m_extraAttacks
)
2224 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2225 if(m_extraAttacks
> 0)
2233 uint32 damage
= CalculateDamage (attType
, false);
2235 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, meleeSchoolMask
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
2237 if (hitInfo
& HITINFO_MISS
)
2239 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2243 SendAttackStateUpdate (hitInfo
, pVictim
, 1, meleeSchoolMask
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
2245 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
2246 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
2250 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, meleeSchoolMask
, NULL
, true);
2252 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
2254 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
2255 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
,attType
);
2259 if (GetTypeId() == TYPEID_PLAYER
)
2260 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2261 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2263 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
2264 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
2266 // extra attack only at any non extra attack (normal case)
2267 if(!extra
&& extraAttacks
)
2269 while(m_extraAttacks
)
2271 AttackerStateUpdate(pVictim
, BASE_ATTACK
, true);
2272 if(m_extraAttacks
> 0)
2278 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (Unit
const *pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
2280 // Miss chance based on melee
2281 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2283 // Critical hit chance
2284 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2285 // this is to avoid compiler issue when declaring variables inside if
2286 float block_chance
, parry_chance
, dodge_chance
;
2288 // cannot be dodged/parried/blocked
2289 if(spellInfo
->Attributes
& SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK
)
2291 block_chance
= 0.0f
;
2292 parry_chance
= 0.0f
;
2293 dodge_chance
= 0.0f
;
2297 // parry can be avoided only by some abilities
2298 parry_chance
= pVictim
->GetUnitParryChance();
2299 // block might be bypassed by it as well
2300 block_chance
= pVictim
->GetUnitBlockChance();
2301 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2302 dodge_chance
= pVictim
->GetUnitDodgeChance();
2305 // Only players can have Talent&Spell bonuses
2306 if (GetTypeId() == TYPEID_PLAYER
)
2308 // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura
2309 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, spellInfo
->SchoolMask
);
2311 if( dodge_chance
!= 0.0f
) // if dodge chance is already 0, ignore talents for speed
2313 AuraList
const& mCanNotBeDodge
= GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT
);
2314 for(AuraList::const_iterator i
= mCanNotBeDodge
.begin(); i
!= mCanNotBeDodge
.end(); ++i
)
2316 // can't be dodged rogue finishing move
2317 if((*i
)->GetModifier()->m_miscvalue
== VICTIMSTATE_DODGE
)
2319 if(spellInfo
->SpellFamilyName
==SPELLFAMILY_ROGUE
&& (spellInfo
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
))
2321 dodge_chance
= 0.0f
;
2330 if(Player
* modOwner
= GetSpellModOwner())
2331 modOwner
->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
2333 DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance
,crit_chance
,dodge_chance
,parry_chance
, block_chance
);
2335 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);
2338 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst(const Unit
*pVictim
, WeaponAttackType attType
) const
2340 // This is only wrapper
2342 // Miss chance based on melee
2343 float miss_chance
= MeleeMissChanceCalc(pVictim
, attType
);
2345 // Critical hit chance
2346 float crit_chance
= GetUnitCriticalChance(attType
, pVictim
);
2348 // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
2349 float dodge_chance
= pVictim
->GetUnitDodgeChance();
2350 float block_chance
= pVictim
->GetUnitBlockChance();
2351 float parry_chance
= pVictim
->GetUnitParryChance();
2353 // Useful if want to specify crit & miss chances for melee, else it could be removed
2354 DEBUG_LOG("MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance
,crit_chance
,dodge_chance
,parry_chance
,block_chance
);
2356 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);
2359 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
2361 if(pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2362 return MELEE_HIT_EVADE
;
2364 int32 attackerMaxSkillValueForLevel
= GetMaxSkillValueForLevel(pVictim
);
2365 int32 victimMaxSkillValueForLevel
= pVictim
->GetMaxSkillValueForLevel(this);
2367 int32 attackerWeaponSkill
= GetWeaponSkillValue(attType
,pVictim
);
2368 int32 victimDefenseSkill
= pVictim
->GetDefenseSkillValue(this);
2370 // bonus from skills is 0.04%
2371 int32 skillBonus
= 4 * ( attackerWeaponSkill
- victimMaxSkillValueForLevel
);
2372 int32 skillBonus2
= 4 * ( attackerMaxSkillValueForLevel
- victimDefenseSkill
);
2373 int32 sum
= 0, tmp
= 0;
2374 int32 roll
= urand (0, 10000);
2376 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2377 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
2378 roll
, miss_chance
, dodge_chance
, parry_chance
, block_chance
, crit_chance
);
2382 if (tmp
> 0 && roll
< (sum
+= tmp
))
2384 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2385 return MELEE_HIT_MISS
;
2388 // always crit against a sitting target (except 0 crit chance)
2389 if( pVictim
->GetTypeId() == TYPEID_PLAYER
&& crit_chance
> 0 && !pVictim
->IsStandState() )
2391 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2392 return MELEE_HIT_CRIT
;
2397 // only players can't dodge if attacker is behind
2398 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& !pVictim
->HasInArc(M_PI
,this))
2400 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
2404 // Reduce dodge chance by attacker expertise rating
2405 if (GetTypeId() == TYPEID_PLAYER
)
2406 dodge_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2408 // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2409 dodge_chance
+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
, VICTIMSTATE_DODGE
);
2412 if ( (tmp
> 0) // check if unit _can_ dodge
2413 && ((tmp
-= skillBonus
) > 0)
2414 && roll
< (sum
+= tmp
))
2416 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2417 return MELEE_HIT_DODGE
;
2421 // parry & block chances
2423 // check if attack comes from behind, nobody can parry or block if attacker is behind
2424 if (!pVictim
->HasInArc(M_PI
,this))
2426 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2430 // Reduce parry chance by attacker expertise rating
2431 if (GetTypeId() == TYPEID_PLAYER
)
2432 parry_chance
-= int32(((Player
*)this)->GetExpertiseDodgeOrParryReduction(attType
)*100);
2434 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_PARRY
) )
2436 int32 tmp
= int32(parry_chance
);
2437 if ( (tmp
> 0) // check if unit _can_ parry
2438 && ((tmp
-= skillBonus
) > 0)
2439 && (roll
< (sum
+= tmp
)))
2441 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2442 return MELEE_HIT_PARRY
;
2446 if(pVictim
->GetTypeId()==TYPEID_PLAYER
|| !(((Creature
*)pVictim
)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_BLOCK
) )
2449 if ( (tmp
> 0) // check if unit _can_ block
2450 && ((tmp
-= skillBonus
) > 0)
2451 && (roll
< (sum
+= tmp
)))
2454 tmp
= crit_chance
+ skillBonus2
;
2455 if ( GetTypeId() == TYPEID_PLAYER
&& SpellCasted
&& tmp
> 0 )
2457 if ( roll_chance_i(tmp
/100))
2459 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT");
2460 return MELEE_HIT_BLOCK_CRIT
;
2463 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2464 return MELEE_HIT_BLOCK
;
2470 tmp
= crit_chance
+ skillBonus2
;
2472 if (tmp
> 0 && roll
< (sum
+= tmp
))
2474 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2475 return MELEE_HIT_CRIT
;
2478 // 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)
2479 if( attType
!= RANGED_ATTACK
&& !SpellCasted
&&
2480 (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet()) &&
2481 pVictim
->GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)pVictim
)->isPet() &&
2482 getLevel() < pVictim
->getLevelForTarget(this) )
2484 // cap possible value (with bonuses > max skill)
2485 int32 skill
= attackerWeaponSkill
;
2486 int32 maxskill
= attackerMaxSkillValueForLevel
;
2487 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2489 tmp
= (10 + (victimDefenseSkill
- skill
)) * 100;
2490 tmp
= tmp
> 4000 ? 4000 : tmp
;
2491 if (roll
< (sum
+= tmp
))
2493 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2494 return MELEE_HIT_GLANCING
;
2498 if(GetTypeId()!=TYPEID_PLAYER
&& !(((Creature
*)this)->GetCreatureInfo()->flags_extra
& CREATURE_FLAG_EXTRA_NO_CRUSH
) && !((Creature
*)this)->isPet() )
2500 // mobs can score crushing blows if they're 3 or more levels above victim
2501 // or when their weapon skill is 15 or more above victim's defense skill
2502 tmp
= victimDefenseSkill
;
2503 int32 tmpmax
= victimMaxSkillValueForLevel
;
2504 // having defense above your maximum (from items, talents etc.) has no effect
2505 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2506 // tmp = mob's level * 5 - player's current defense skill
2507 tmp
= attackerMaxSkillValueForLevel
- tmp
;
2510 // add 2% chance per lacking skill point, min. is 15%
2511 tmp
= tmp
* 200 - 1500;
2512 if (roll
< (sum
+= tmp
))
2514 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2515 return MELEE_HIT_CRUSHING
;
2520 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2521 return MELEE_HIT_NORMAL
;
2524 uint32
Unit::CalculateDamage (WeaponAttackType attType
, bool normalized
)
2526 float min_damage
, max_damage
;
2528 if (normalized
&& GetTypeId()==TYPEID_PLAYER
)
2529 ((Player
*)this)->CalculateMinMaxDamage(attType
,normalized
,min_damage
, max_damage
);
2535 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2536 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2539 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2540 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2543 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2544 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2546 // Just for good manner
2554 if (min_damage
> max_damage
)
2556 std::swap(min_damage
,max_damage
);
2559 if(max_damage
== 0.0f
)
2562 return urand((uint32
)min_damage
, (uint32
)max_damage
);
2565 float Unit::CalculateLevelPenalty(SpellEntry
const* spellProto
) const
2567 if(spellProto
->spellLevel
<= 0)
2570 float LvlPenalty
= 0.0f
;
2572 if(spellProto
->spellLevel
< 20)
2573 LvlPenalty
= 20.0f
- spellProto
->spellLevel
* 3.75f
;
2574 float LvlFactor
= (float(spellProto
->spellLevel
) + 6.0f
) / float(getLevel());
2575 if(LvlFactor
> 1.0f
)
2578 return (100.0f
- LvlPenalty
) * LvlFactor
/ 100.0f
;
2581 void Unit::SendAttackStart(Unit
* pVictim
)
2583 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2584 data
<< uint64(GetGUID());
2585 data
<< uint64(pVictim
->GetGUID());
2587 SendMessageToSet(&data
, true);
2588 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2591 void Unit::SendAttackStop(Unit
* victim
)
2596 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2597 data
.append(GetPackGUID());
2598 data
.append(victim
->GetPackGUID()); // can be 0x00...
2599 data
<< uint32(0); // can be 0x1
2600 SendMessageToSet(&data
, true);
2601 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2603 /*if(victim->GetTypeId() == TYPEID_UNIT)
2604 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2608 // Melee based spells can be miss, parry or dodge on this step
2609 // Crit or block - determined on damage calculation phase! (and can be both in some time)
2610 float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
2612 // Calculate hit chance (more correct for chance mod)
2615 // PvP - PvE melee chances
2616 int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7;
2617 int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim);
2619 HitChance = 95 - leveldif;
2621 HitChance = 93 - (leveldif - 2) * lchance;
2623 // Hit chance depends from victim auras
2624 if(attType == RANGED_ATTACK)
2625 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE);
2627 HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE);
2629 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2630 if(Player *modOwner = GetSpellModOwner())
2631 modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance);
2634 float miss_chance= 100.0f - HitChance;
2636 // Bonuses from attacker aura and ratings
2637 if (attType == RANGED_ATTACK)
2638 miss_chance -= m_modRangedHitChance;
2640 miss_chance -= m_modMeleeHitChance;
2642 // bonus from skills is 0.04%
2643 miss_chance -= skillDiff * 0.04f;
2645 // Limit miss chance from 0 to 60%
2646 if (miss_chance < 0.0f)
2648 if (miss_chance > 60.0f)
2653 // Melee based spells hit result calculations
2654 SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
2656 WeaponAttackType attType = BASE_ATTACK;
2658 if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2659 attType = RANGED_ATTACK;
2661 // bonus from skills is 0.04% per skill Diff
2662 int32 attackerWeaponSkill = int32(GetWeaponSkillValue(attType,pVictim));
2663 int32 skillDiff = attackerWeaponSkill - int32(pVictim->GetMaxSkillValueForLevel(this));
2664 int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this));
2666 uint32 roll = urand (0, 10000);
2667 uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell)*100.0f);
2670 uint32 tmp = missChance;
2672 return SPELL_MISS_MISS;
2674 // Same spells cannot be parry/dodge
2675 if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
2676 return SPELL_MISS_NONE;
2678 // Ranged attack can`t miss too
2679 if (attType == RANGED_ATTACK)
2680 return SPELL_MISS_NONE;
2682 bool attackFromBehind = !pVictim->HasInArc(M_PI,this);
2685 int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4;
2686 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2687 dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE);
2689 // Reduce dodge chance by attacker expertise rating
2690 if (GetTypeId() == TYPEID_PLAYER)
2691 dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2692 if (dodgeChance < 0)
2695 // Can`t dodge from behind in PvP (but its possible in PvE)
2696 if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind)
2699 // Rogue talent`s cant be dodged
2700 AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
2701 for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i)
2703 if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move
2705 if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE))
2715 return SPELL_MISS_DODGE;
2718 int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4;
2719 // Reduce parry chance by attacker expertise rating
2720 if (GetTypeId() == TYPEID_PLAYER)
2721 parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
2722 // Can`t parry from behind
2723 if (parryChance < 0 || attackFromBehind)
2728 return SPELL_MISS_PARRY;
2730 return SPELL_MISS_NONE;
2733 // TODO need use unit spell resistances in calculations
2734 SpellMissInfo
Unit::MagicSpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
)
2736 // Can`t miss on dead target (on skinning for example)
2737 if (!pVictim
->isAlive())
2738 return SPELL_MISS_NONE
;
2740 SpellSchoolMask schoolMask
= GetSpellSchoolMask(spell
);
2741 // PvP - PvE spell misschances per leveldif > 2
2742 int32 lchance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 7 : 11;
2743 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2745 // Base hit chance from attacker and victim levels
2748 modHitChance
= 96 - leveldif
;
2750 modHitChance
= 94 - (leveldif
- 2) * lchance
;
2752 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
2753 if(Player
*modOwner
= GetSpellModOwner())
2754 modOwner
->ApplySpellMod(spell
->Id
, SPELLMOD_RESIST_MISS_CHANCE
, modHitChance
);
2755 // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
2756 modHitChance
+=GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT
, schoolMask
);
2757 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2758 modHitChance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
, schoolMask
);
2759 // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
2760 if (IsAreaOfEffectSpell(spell
))
2761 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE
);
2762 // Reduce spell hit chance for dispel mechanic spells from victim SPELL_AURA_MOD_DISPEL_RESIST
2763 if (IsDispelSpell(spell
))
2764 modHitChance
-=pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_DISPEL_RESIST
);
2765 // Chance resist mechanic (select max value from every mechanic spell effect)
2766 int32 resist_mech
= 0;
2767 // Get effects mechanic and chance
2768 for(int eff
= 0; eff
< 3; ++eff
)
2770 int32 effect_mech
= GetEffectMechanic(spell
, eff
);
2773 int32 temp
= pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE
, effect_mech
);
2774 if (resist_mech
< temp
)
2779 modHitChance
-=resist_mech
;
2781 // Chance resist debuff
2782 modHitChance
-=pVictim
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE
, int32(spell
->Dispel
));
2784 int32 HitChance
= modHitChance
* 100;
2785 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2786 HitChance
+= int32(m_modSpellHitChance
*100.0f
);
2788 // Decrease hit chance from victim rating bonus
2789 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2790 HitChance
-= int32(((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_SPELL
)*100.0f
);
2792 if (HitChance
< 100) HitChance
= 100;
2793 if (HitChance
> 9900) HitChance
= 9900;
2795 uint32 rand
= urand(0,10000);
2796 if (rand
> HitChance
)
2797 return SPELL_MISS_RESIST
;
2798 return SPELL_MISS_NONE
;
2801 SpellMissInfo
Unit::SpellHitResult(Unit
*pVictim
, SpellEntry
const *spell
, bool CanReflect
)
2803 // Return evade for units in evade mode
2804 if (pVictim
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pVictim
)->IsInEvadeMode())
2805 return SPELL_MISS_EVADE
;
2807 // Check for immune (use charges)
2808 if (pVictim
->IsImmunedToSpell(spell
,true))
2809 return SPELL_MISS_IMMUNE
;
2811 // All positive spells can`t miss
2812 // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
2813 if (IsPositiveSpell(spell
->Id
))
2814 return SPELL_MISS_NONE
;
2816 // Check for immune (use charges)
2817 if (pVictim
->IsImmunedToDamage(GetSpellSchoolMask(spell
),true))
2818 return SPELL_MISS_IMMUNE
;
2820 // Try victim reflect spell
2823 // specialized first
2824 Unit::AuraList
const& mReflectSpellsSchool
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL
);
2825 for(Unit::AuraList::const_iterator i
= mReflectSpellsSchool
.begin(); i
!= mReflectSpellsSchool
.end(); ++i
)
2827 if((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spell
))
2829 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2830 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2832 if((*i
)->m_procCharges
> 0)
2834 --(*i
)->m_procCharges
;
2835 if((*i
)->m_procCharges
==0)
2836 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2838 return SPELL_MISS_REFLECT
;
2843 // generic reflection
2844 Unit::AuraList
const& mReflectSpells
= pVictim
->GetAurasByType(SPELL_AURA_REFLECT_SPELLS
);
2845 for(Unit::AuraList::const_iterator i
= mReflectSpells
.begin(); i
!= mReflectSpells
.end(); ++i
)
2847 int32 reflectchance
= (*i
)->GetModifier()->m_amount
;
2848 if (reflectchance
> 0 && roll_chance_i(reflectchance
))
2850 if((*i
)->m_procCharges
> 0)
2852 --(*i
)->m_procCharges
;
2853 if((*i
)->m_procCharges
==0)
2854 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
2856 return SPELL_MISS_REFLECT
;
2861 // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
2862 for (int i
=0;i
<3;i
++)
2864 if (spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE
||
2865 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
||
2866 spell
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
||
2867 spell
->Effect
[i
] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
)
2868 return SPELL_MISS_NONE
;
2871 // TODO need use this code for spell hit result calculation
2872 // now code commented for computability
2873 switch (spell
->DmgClass
)
2875 case SPELL_DAMAGE_CLASS_RANGED
:
2876 case SPELL_DAMAGE_CLASS_MELEE
:
2877 // return MeleeSpellHitResult(pVictim, spell);
2878 return SPELL_MISS_NONE
;
2879 case SPELL_DAMAGE_CLASS_NONE
:
2880 case SPELL_DAMAGE_CLASS_MAGIC
:
2881 return MagicSpellHitResult(pVictim
, spell
);
2883 return SPELL_MISS_NONE
;
2886 float Unit::MeleeMissChanceCalc(const Unit
*pVictim
, WeaponAttackType attType
) const
2891 // Base misschance 5%
2892 float misschance
= 5.0f
;
2894 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2895 if (haveOffhandWeapon() && attType
!= RANGED_ATTACK
)
2897 bool isNormal
= false;
2898 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2900 if( m_currentSpells
[i
] && (GetSpellSchoolMask(m_currentSpells
[i
]->m_spellInfo
) & SPELL_SCHOOL_MASK_NORMAL
) )
2906 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2916 // PvP : PvE melee misschances per leveldif > 2
2917 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 5 : 7;
2919 int32 leveldif
= int32(pVictim
->getLevelForTarget(this)) - int32(getLevelForTarget(pVictim
));
2923 // Hit chance from attacker based on ratings and auras
2924 float m_modHitChance
;
2925 if (attType
== RANGED_ATTACK
)
2926 m_modHitChance
= m_modRangedHitChance
;
2928 m_modHitChance
= m_modMeleeHitChance
;
2931 misschance
+= (leveldif
- m_modHitChance
);
2933 misschance
+= ((leveldif
- 2) * chance
- m_modHitChance
);
2935 // Hit chance for victim based on ratings
2936 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
2938 if (attType
== RANGED_ATTACK
)
2939 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_RANGED
);
2941 misschance
+= ((Player
*)pVictim
)->GetRatingBonusValue(CR_HIT_TAKEN_MELEE
);
2944 // Modify miss chance by victim auras
2945 if(attType
== RANGED_ATTACK
)
2946 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
);
2948 misschance
-= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
);
2950 // Modify miss chance from skill difference ( bonus from skills is 0.04% )
2951 int32 skillBonus
= int32(GetWeaponSkillValue(attType
,pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this));
2952 misschance
-= skillBonus
* 0.04f
;
2954 // Limit miss chance from 0 to 60%
2955 if ( misschance
< 0.0f
)
2957 if ( misschance
> 60.0f
)
2963 uint32
Unit::GetDefenseSkillValue(Unit
const* target
) const
2965 if(GetTypeId() == TYPEID_PLAYER
)
2967 // in PvP use full skill instead current skill value
2968 uint32 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
2969 ? ((Player
*)this)->GetMaxSkillValue(SKILL_DEFENSE
)
2970 : ((Player
*)this)->GetSkillValue(SKILL_DEFENSE
);
2971 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_DEFENSE_SKILL
));
2975 return GetUnitMeleeSkill(target
);
2978 float Unit::GetUnitDodgeChance() const
2980 if(hasUnitState(UNIT_STAT_STUNNED
))
2982 if( GetTypeId() == TYPEID_PLAYER
)
2983 return GetFloatValue(PLAYER_DODGE_PERCENTAGE
);
2986 if(((Creature
const*)this)->isTotem())
2991 dodge
+= GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT
);
2992 return dodge
> 0.0f
? dodge
: 0.0f
;
2997 float Unit::GetUnitParryChance() const
2999 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3002 float chance
= 0.0f
;
3004 if(GetTypeId() == TYPEID_PLAYER
)
3006 Player
const* player
= (Player
const*)this;
3007 if(player
->CanParry() )
3009 Item
*tmpitem
= player
->GetWeaponForAttack(BASE_ATTACK
,true);
3011 tmpitem
= player
->GetWeaponForAttack(OFF_ATTACK
,true);
3014 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
3017 else if(GetTypeId() == TYPEID_UNIT
)
3019 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
3022 chance
+= GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT
);
3026 return chance
> 0.0f
? chance
: 0.0f
;
3029 float Unit::GetUnitBlockChance() const
3031 if ( IsNonMeleeSpellCasted(false) || hasUnitState(UNIT_STAT_STUNNED
))
3034 if(GetTypeId() == TYPEID_PLAYER
)
3036 Player
const* player
= (Player
const*)this;
3037 if(player
->CanBlock() )
3039 Item
*tmpitem
= player
->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3040 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
3041 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
3043 // is player but has no block ability or no not broken shield equipped
3048 if(((Creature
const*)this)->isTotem())
3053 block
+= GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT
);
3054 return block
> 0.0f
? block
: 0.0f
;
3059 float Unit::GetUnitCriticalChance(WeaponAttackType attackType
, const Unit
*pVictim
) const
3063 if(GetTypeId() == TYPEID_PLAYER
)
3068 crit
= GetFloatValue( PLAYER_CRIT_PERCENTAGE
);
3071 crit
= GetFloatValue( PLAYER_OFFHAND_CRIT_PERCENTAGE
);
3074 crit
= GetFloatValue( PLAYER_RANGED_CRIT_PERCENTAGE
);
3076 // Just for good manner
3085 crit
+= GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PERCENT
);
3089 if(attackType
== RANGED_ATTACK
)
3090 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
);
3092 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
);
3094 crit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
3096 // reduce crit chance from Rating for players
3097 if (pVictim
->GetTypeId()==TYPEID_PLAYER
)
3099 if (attackType
==RANGED_ATTACK
)
3100 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_RANGED
);
3102 crit
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
);
3110 uint32
Unit::GetWeaponSkillValue (WeaponAttackType attType
, Unit
const* target
) const
3113 if(GetTypeId() == TYPEID_PLAYER
)
3115 Item
* item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
3117 // feral or unarmed skill only for base attack
3118 if(attType
!= BASE_ATTACK
&& !item
)
3121 if(((Player
*)this)->IsInFeralForm())
3122 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
3124 // weapon skill or (unarmed for base attack)
3125 uint32 skill
= item
? item
->GetSkill() : SKILL_UNARMED
;
3127 // in PvP use full skill instead current skill value
3128 value
= (target
&& target
->GetTypeId() == TYPEID_PLAYER
)
3129 ? ((Player
*)this)->GetMaxSkillValue(skill
)
3130 : ((Player
*)this)->GetSkillValue(skill
);
3131 // Modify value from ratings
3132 value
+= uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL
));
3135 case BASE_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND
));break;
3136 case OFF_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND
));break;
3137 case RANGED_ATTACK
: value
+=uint32(((Player
*)this)->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED
));break;
3141 value
= GetUnitMeleeSkill(target
);
3145 void Unit::_UpdateSpells( uint32 time
)
3147 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
3148 _UpdateAutoRepeatSpell();
3150 // remove finished spells from current pointers
3151 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3153 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
3155 m_currentSpells
[i
]->SetReferencedFromCurrent(false);
3156 m_currentSpells
[i
] = NULL
; // remove pointer
3160 // TODO: Find a better way to prevent crash when multiple auras are removed.
3162 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3164 (*i
).second
->SetUpdated(false);
3166 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
3172 // prevent double update
3173 if ((*i
).second
->IsUpdated())
3175 (*i
).second
->SetUpdated(true);
3176 (*i
).second
->Update( time
);
3177 // several auras can be deleted due to update
3180 if (m_Auras
.empty()) break;
3181 next
= m_Auras
.begin();
3187 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3191 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
3206 if(!m_gameObj
.empty())
3208 std::list
<GameObject
*>::iterator ite1
, dnext1
;
3209 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
3212 //(*i)->Update( difftime );
3213 if( !(*ite1
)->isSpawned() )
3215 (*ite1
)->SetOwnerGUID(0);
3216 (*ite1
)->SetRespawnTime(0);
3218 dnext1
= m_gameObj
.erase(ite1
);
3226 void Unit::_UpdateAutoRepeatSpell()
3228 //check "realtime" interrupts
3229 if ( (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) )
3231 // cancel wand shoot
3232 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3233 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3234 m_AutoRepeatFirstCast
= true;
3239 if ( m_AutoRepeatFirstCast
&& getAttackTimer(RANGED_ATTACK
) < 500 )
3240 setAttackTimer(RANGED_ATTACK
,500);
3241 m_AutoRepeatFirstCast
= false;
3244 if (isAttackReady(RANGED_ATTACK
))
3246 // Check if able to cast
3247 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast(true))
3249 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3254 Spell
* spell
= new Spell(this, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
, true, 0);
3255 spell
->prepare(&(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_targets
));
3257 // all went good, reset attack
3258 resetAttackTimer(RANGED_ATTACK
);
3262 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
3264 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3266 uint32 CSpellType
= pSpell
->GetCurrentContainer();
3268 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
3270 // break same type spell if it is not delayed
3271 InterruptSpell(CSpellType
,false);
3273 // special breakage effects:
3276 case CURRENT_GENERIC_SPELL
:
3278 // generic spells always break channeled not delayed spells
3279 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3281 // autorepeat breaking
3282 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3284 // break autorepeat if not Auto Shot
3285 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
3286 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3287 m_AutoRepeatFirstCast
= true;
3291 case CURRENT_CHANNELED_SPELL
:
3293 // channel spells always break generic non-delayed and any channeled spells
3294 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3295 InterruptSpell(CURRENT_CHANNELED_SPELL
);
3297 // it also does break autorepeat if not Auto Shot
3298 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
3299 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
3300 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
3303 case CURRENT_AUTOREPEAT_SPELL
:
3305 // only Auto Shoot does not break anything
3306 if (pSpell
->m_spellInfo
->Category
== 351)
3308 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3309 InterruptSpell(CURRENT_GENERIC_SPELL
,false);
3310 InterruptSpell(CURRENT_CHANNELED_SPELL
,false);
3312 // special action: set first cast flag
3313 m_AutoRepeatFirstCast
= true;
3318 // other spell types don't break anything now
3322 // current spell (if it is still here) may be safely deleted now
3323 if (m_currentSpells
[CSpellType
])
3324 m_currentSpells
[CSpellType
]->SetReferencedFromCurrent(false);
3326 // set new current spell
3327 m_currentSpells
[CSpellType
] = pSpell
;
3328 pSpell
->SetReferencedFromCurrent(true);
3331 void Unit::InterruptSpell(uint32 spellType
, bool withDelayed
)
3333 assert(spellType
< CURRENT_MAX_SPELL
);
3335 if(m_currentSpells
[spellType
] && (withDelayed
|| m_currentSpells
[spellType
]->getState() != SPELL_STATE_DELAYED
) )
3337 // send autorepeat cancel message for autorepeat spells
3338 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
3340 if(GetTypeId()==TYPEID_PLAYER
)
3341 ((Player
*)this)->SendAutoRepeatCancel();
3344 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
3345 m_currentSpells
[spellType
]->cancel();
3346 m_currentSpells
[spellType
]->SetReferencedFromCurrent(false);
3347 m_currentSpells
[spellType
] = NULL
;
3351 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
) const
3353 // We don't do loop here to explicitly show that melee spell is excluded.
3354 // Maybe later some special spells will be excluded too.
3356 // generic spells are casted when they are not finished and not delayed
3357 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
3358 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3359 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3362 // channeled spells may be delayed, but they are still considered casted
3363 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
3364 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
3367 // autorepeat spells may be finished or delayed, but they are still considered casted
3368 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
3374 void Unit::InterruptNonMeleeSpells(bool withDelayed
, uint32 spell_id
)
3376 // generic spells are interrupted if they are not finished or delayed
3377 if (m_currentSpells
[CURRENT_GENERIC_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->m_spellInfo
->Id
==spell_id
))
3379 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3380 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3381 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
3382 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetReferencedFromCurrent(false);
3383 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
3386 // autorepeat spells are interrupted if they are not finished or delayed
3387 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Id
==spell_id
))
3389 // send disable autorepeat packet in any case
3390 if(GetTypeId()==TYPEID_PLAYER
)
3391 ((Player
*)this)->SendAutoRepeatCancel();
3393 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
3394 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
3395 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
3396 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetReferencedFromCurrent(false);
3397 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
3400 // channeled spells are interrupted if they are not finished, even if they are delayed
3401 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
] && (!spell_id
|| m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
==spell_id
))
3403 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
3404 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
3405 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetReferencedFromCurrent(false);
3406 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
3410 Spell
* Unit::FindCurrentSpellBySpellId(uint32 spell_id
) const
3412 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
3413 if(m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
==spell_id
)
3414 return m_currentSpells
[i
];
3418 bool Unit::isInFront(Unit
const* target
, float distance
, float arc
) const
3420 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
3423 void Unit::SetInFront(Unit
const* target
)
3425 SetOrientation(GetAngle(target
));
3428 bool Unit::isInBack(Unit
const* target
, float distance
, float arc
) const
3430 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
3433 bool Unit::isInAccessablePlaceFor(Creature
const* c
) const
3436 return c
->canSwim();
3438 return c
->canWalk() || c
->canFly();
3441 bool Unit::IsInWater() const
3443 return MapManager::Instance().GetBaseMap(GetMapId())->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
3446 bool Unit::IsUnderWater() const
3448 return MapManager::Instance().GetBaseMap(GetMapId())->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
3451 void Unit::DeMorph()
3453 SetDisplayId(GetNativeDisplayId());
3456 int32
Unit::GetTotalAuraModifier(AuraType auratype
) const
3460 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3461 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3462 modifier
+= (*i
)->GetModifier()->m_amount
;
3467 float Unit::GetTotalAuraMultiplier(AuraType auratype
) const
3469 float multiplier
= 1.0f
;
3471 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3472 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3473 multiplier
*= (100.0f
+ (*i
)->GetModifier()->m_amount
)/100.0f
;
3478 int32
Unit::GetMaxPositiveAuraModifier(AuraType auratype
) const
3482 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3483 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3484 if ((*i
)->GetModifier()->m_amount
> modifier
)
3485 modifier
= (*i
)->GetModifier()->m_amount
;
3490 int32
Unit::GetMaxNegativeAuraModifier(AuraType auratype
) const
3494 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3495 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3496 if ((*i
)->GetModifier()->m_amount
< modifier
)
3497 modifier
= (*i
)->GetModifier()->m_amount
;
3502 int32
Unit::GetTotalAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3506 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3507 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3509 Modifier
* mod
= (*i
)->GetModifier();
3510 if (mod
->m_miscvalue
& misc_mask
)
3511 modifier
+= mod
->m_amount
;
3516 float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3518 float multiplier
= 1.0f
;
3520 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3521 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3523 Modifier
* mod
= (*i
)->GetModifier();
3524 if (mod
->m_miscvalue
& misc_mask
)
3525 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3530 int32
Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3534 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3535 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3537 Modifier
* mod
= (*i
)->GetModifier();
3538 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
> modifier
)
3539 modifier
= mod
->m_amount
;
3545 int32
Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype
, uint32 misc_mask
) const
3549 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3550 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3552 Modifier
* mod
= (*i
)->GetModifier();
3553 if (mod
->m_miscvalue
& misc_mask
&& mod
->m_amount
< modifier
)
3554 modifier
= mod
->m_amount
;
3560 int32
Unit::GetTotalAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3564 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3565 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3567 Modifier
* mod
= (*i
)->GetModifier();
3568 if (mod
->m_miscvalue
== misc_value
)
3569 modifier
+= mod
->m_amount
;
3574 float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype
, int32 misc_value
) const
3576 float multiplier
= 1.0f
;
3578 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3579 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3581 Modifier
* mod
= (*i
)->GetModifier();
3582 if (mod
->m_miscvalue
== misc_value
)
3583 multiplier
*= (100.0f
+ mod
->m_amount
)/100.0f
;
3588 int32
Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3592 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3593 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3595 Modifier
* mod
= (*i
)->GetModifier();
3596 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
> modifier
)
3597 modifier
= mod
->m_amount
;
3603 int32
Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype
, int32 misc_value
) const
3607 AuraList
const& mTotalAuraList
= GetAurasByType(auratype
);
3608 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
3610 Modifier
* mod
= (*i
)->GetModifier();
3611 if (mod
->m_miscvalue
== misc_value
&& mod
->m_amount
< modifier
)
3612 modifier
= mod
->m_amount
;
3618 bool Unit::AddAura(Aura
*Aur
)
3620 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3621 if( !isAlive() && Aur
->GetId() != 20584 && Aur
->GetId() != 8326 && Aur
->GetId() != 2584 &&
3622 (GetTypeId()!=TYPEID_PLAYER
|| !((Player
*)this)->GetSession()->PlayerLoading()) )
3628 if(Aur
->GetTarget() != this)
3630 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
3631 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
3632 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
3637 SpellEntry
const* aurSpellInfo
= Aur
->GetSpellProto();
3639 spellEffectPair spair
= spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex());
3640 AuraMap::iterator i
= m_Auras
.find( spair
);
3642 // take out same spell
3643 if (i
!= m_Auras
.end())
3645 // passive and persistent auras can stack with themselves any number of times
3646 if (!Aur
->IsPassive() && !Aur
->IsPersistent())
3648 // replace aura if next will > spell StackAmount
3649 if(aurSpellInfo
->StackAmount
)
3651 if(m_Auras
.count(spair
) >= aurSpellInfo
->StackAmount
)
3652 RemoveAura(i
,AURA_REMOVE_BY_STACK
);
3654 // if StackAmount==0 not allow auras from same caster
3657 for(AuraMap::iterator i2
= m_Auras
.lower_bound(spair
); i2
!= m_Auras
.upper_bound(spair
); ++i2
)
3659 if(i2
->second
->GetCasterGUID()==Aur
->GetCasterGUID())
3661 // can be only single (this check done at _each_ aura add
3662 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3667 switch(aurSpellInfo
->EffectApplyAuraName
[Aur
->GetEffIndex()])
3670 case SPELL_AURA_PERIODIC_DAMAGE
: // allow stack
3671 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
3672 case SPELL_AURA_PERIODIC_LEECH
:
3673 case SPELL_AURA_PERIODIC_HEAL
:
3674 case SPELL_AURA_OBS_MOD_HEALTH
:
3675 case SPELL_AURA_PERIODIC_MANA_LEECH
:
3676 case SPELL_AURA_PERIODIC_ENERGIZE
:
3677 case SPELL_AURA_OBS_MOD_MANA
:
3678 case SPELL_AURA_POWER_BURN_MANA
:
3680 default: // not allow
3681 // can be only single (this check done at _each_ aura add
3682 RemoveAura(i2
,AURA_REMOVE_BY_STACK
);
3694 // passive auras stack with all (except passive spell proc auras)
3695 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
3696 !(Aur
->GetId() == 20584 || Aur
->GetId() == 8326))
3698 if (!RemoveNoStackAurasDueToAura(Aur
))
3701 return false; // couldn't remove conflicting aura with higher rank
3705 // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura)
3706 if (IsSingleTargetSpell(aurSpellInfo
) && Aur
->GetTarget())
3708 // caster pointer can be deleted in time aura remove, find it by guid at each iteration
3711 Unit
* caster
= Aur
->GetCaster();
3712 if(!caster
) // caster deleted and not required adding scAura
3715 bool restart
= false;
3716 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3717 for(AuraList::iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
3719 if( (*itr
)->GetTarget() != Aur
->GetTarget() &&
3720 IsSingleTargetSpells((*itr
)->GetSpellProto(),aurSpellInfo
) )
3722 if ((*itr
)->IsInUse())
3724 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());
3727 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
3736 scAuras
.push_back(Aur
);
3742 // add aura, register in lists and arrays
3744 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
3745 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3747 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
3750 Aur
->ApplyModifier(true,true);
3751 sLog
.outDebug("Aura %u now is in use", Aur
->GetModifier()->m_auraname
);
3755 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
3757 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
3760 AuraMap::iterator i
,next
;
3761 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3765 uint32 i_spellId
= (*i
).second
->GetId();
3766 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
3768 if(spellmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
3770 RemoveAurasDueToSpell(i_spellId
);
3772 if( m_Auras
.empty() )
3775 next
= m_Auras
.begin();
3781 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
3786 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
3790 uint32 spellId
= Aur
->GetId();
3791 uint32 effIndex
= Aur
->GetEffIndex();
3793 SpellSpecific spellId_spec
= GetSpellSpecific(spellId
);
3795 AuraMap::iterator i
,next
;
3796 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
3800 if (!(*i
).second
) continue;
3802 SpellEntry
const* i_spellProto
= (*i
).second
->GetSpellProto();
3807 uint32 i_spellId
= i_spellProto
->Id
;
3809 if(IsPassiveSpell(i_spellId
))
3811 if(IsPassiveStackableSpell(i_spellId
))
3814 // passive non-stackable spells not stackable only with another rank of same spell
3815 if (!spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3819 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
3821 if(i_spellId
== spellId
) continue;
3823 bool is_triggered_by_spell
= false;
3824 // prevent triggered aura of removing aura that triggered it
3825 for(int j
= 0; j
< 3; ++j
)
3826 if (i_spellProto
->EffectTriggerSpell
[j
] == spellProto
->Id
)
3827 is_triggered_by_spell
= true;
3828 if (is_triggered_by_spell
) continue;
3830 for(int j
= 0; j
< 3; ++j
)
3832 // prevent remove dummy triggered spells at next effect aura add
3833 switch(spellProto
->Effect
[j
]) // main spell auras added added after triggered spell
3835 case SPELL_EFFECT_DUMMY
:
3838 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
3843 if(is_triggered_by_spell
)
3846 // prevent remove form main spell by triggered passive spells
3847 switch(i_spellProto
->EffectApplyAuraName
[j
]) // main aura added before triggered spell
3849 case SPELL_AURA_MOD_SHAPESHIFT
:
3852 case 24858: if(spellId
==24905) is_triggered_by_spell
= true; break;
3853 case 33891: if(spellId
==5420 || spellId
==34123) is_triggered_by_spell
= true; break;
3854 case 34551: if(spellId
==22688) is_triggered_by_spell
= true; break;
3860 if(!is_triggered_by_spell
)
3862 SpellSpecific i_spellId_spec
= GetSpellSpecific(i_spellId
);
3864 bool is_sspc
= IsSingleFromSpellSpecificPerCaster(spellId_spec
,i_spellId_spec
);
3866 if( is_sspc
&& Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID() )
3868 // cannot remove higher rank
3869 if (spellmgr
.IsRankSpellDueToSpell(spellProto
, i_spellId
))
3870 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3873 // Its a parent aura (create this aura in ApplyModifier)
3874 if ((*i
).second
->IsInUse())
3876 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());
3879 RemoveAurasDueToSpell(i_spellId
);
3881 if( m_Auras
.empty() )
3884 next
= m_Auras
.begin();
3886 else if( !is_sspc
&& spellmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) )
3888 // Its a parent aura (create this aura in ApplyModifier)
3889 if ((*i
).second
->IsInUse())
3891 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());
3894 RemoveAurasDueToSpell(i_spellId
);
3896 if( m_Auras
.empty() )
3899 next
= m_Auras
.begin();
3901 // Potions stack aura by aura (elixirs/flask already checked)
3902 else if( spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
&& i_spellProto
->SpellFamilyName
== SPELLFAMILY_POTION
)
3904 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
3906 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
3907 return false; // cannot remove higher rank
3909 // Its a parent aura (create this aura in ApplyModifier)
3910 if ((*i
).second
->IsInUse())
3912 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());
3924 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
, Aura
* except
)
3926 spellEffectPair spair
= spellEffectPair(spellId
, effindex
);
3927 for(AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
3929 if(iter
->second
!=except
)
3932 iter
= m_Auras
.lower_bound(spair
);
3939 void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId
, uint64 casterGUID
, Unit
*dispeler
)
3941 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3943 Aura
*aur
= iter
->second
;
3944 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3946 // Custom dispel case
3947 // Unstable Affliction
3948 if (aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_WARLOCK
&& (aur
->GetSpellProto()->SpellFamilyFlags
& 0x010000000000LL
))
3950 int32 damage
= aur
->GetModifier()->m_amount
*9;
3951 uint64 caster_guid
= aur
->GetCasterGUID();
3954 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3956 // backfire damage and silence
3957 dispeler
->CastCustomSpell(dispeler
, 31117, &damage
, NULL
, NULL
, true, NULL
, NULL
,caster_guid
);
3959 iter
= m_Auras
.begin(); // iterator can be invalidate at cast if self-dispel
3962 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
3969 void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId
, uint64 casterGUID
, Unit
*stealer
)
3971 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3973 Aura
*aur
= iter
->second
;
3974 if (aur
->GetId() == spellId
&& aur
->GetCasterGUID() == casterGUID
)
3976 int32 basePoints
= aur
->GetBasePoints();
3977 // construct the new aura for the attacker
3978 Aura
* new_aur
= CreateAura(aur
->GetSpellProto(), aur
->GetEffIndex(), &basePoints
, stealer
);
3982 // set its duration and maximum duration
3983 // max duration 2 minutes (in msecs)
3984 int32 dur
= aur
->GetAuraDuration();
3985 const int32 max_dur
= 2*MINUTE
*1000;
3986 new_aur
->SetAuraMaxDuration( max_dur
> dur
? dur
: max_dur
);
3987 new_aur
->SetAuraDuration( max_dur
> dur
? dur
: max_dur
);
3989 // add the new aura to stealer
3990 stealer
->AddAura(new_aur
);
3992 // Remove aura as dispel
3993 RemoveAura(iter
, AURA_REMOVE_BY_DISPEL
);
4000 void Unit::RemoveAurasDueToSpellByCancel(uint32 spellId
)
4002 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4004 if (iter
->second
->GetId() == spellId
)
4005 RemoveAura(iter
, AURA_REMOVE_BY_CANCEL
);
4011 void Unit::RemoveAurasWithDispelType( DispelType type
)
4013 // Create dispel mask by dispel type
4014 uint32 dispelMask
= GetDispellMask(type
);
4015 // Dispel all existing auras vs current dispel type
4016 AuraMap
& auras
= GetAuras();
4017 for(AuraMap::iterator itr
= auras
.begin(); itr
!= auras
.end(); )
4019 SpellEntry
const* spell
= itr
->second
->GetSpellProto();
4020 if( (1<<spell
->Dispel
) & dispelMask
)
4023 RemoveAurasDueToSpell(spell
->Id
);
4024 itr
= auras
.begin();
4031 void Unit::RemoveSingleAuraFromStack(uint32 spellId
, uint32 effindex
)
4033 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4034 if(iter
!= m_Auras
.end())
4038 void Unit::RemoveAurasDueToSpell(uint32 spellId
, Aura
* except
)
4040 for (int i
= 0; i
< 3; ++i
)
4041 RemoveAura(spellId
,i
,except
);
4044 void Unit::RemoveAurasDueToItemSpell(Item
* castItem
,uint32 spellId
)
4046 for (int k
=0; k
< 3; ++k
)
4048 spellEffectPair spair
= spellEffectPair(spellId
, k
);
4049 for (AuraMap::iterator iter
= m_Auras
.lower_bound(spair
); iter
!= m_Auras
.upper_bound(spair
);)
4051 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
4054 iter
= m_Auras
.upper_bound(spair
); // overwrite by more appropriate
4062 void Unit::RemoveAurasWithInterruptFlags(uint32 flags
)
4064 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4066 if (iter
->second
->GetSpellProto()->AuraInterruptFlags
& flags
)
4073 void Unit::RemoveNotOwnSingleTargetAuras()
4075 // single target auras from other casters
4076 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
4078 if (iter
->second
->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter
->second
->GetSpellProto()))
4084 // single target auras at other targets
4085 AuraList
& scAuras
= GetSingleCastAuras();
4086 for (AuraList::iterator iter
= scAuras
.begin(); iter
!= scAuras
.end(); )
4089 if (aura
->GetTarget()!=this)
4091 scAuras
.erase(iter
); // explicitly remove, instead waiting remove in RemoveAura
4092 aura
->GetTarget()->RemoveAura(aura
->GetId(),aura
->GetEffIndex());
4093 iter
= scAuras
.begin();
4101 void Unit::RemoveAura(AuraMap::iterator
&i
, AuraRemoveMode mode
)
4103 Aura
* Aur
= i
->second
;
4104 SpellEntry
const* AurSpellInfo
= Aur
->GetSpellProto();
4106 Unit
* caster
= NULL
;
4107 if (IsSingleTargetSpell(AurSpellInfo
))
4109 caster
= Aur
->GetCaster();
4112 AuraList
& scAuras
= caster
->GetSingleCastAuras();
4113 scAuras
.remove(Aur
);
4117 sLog
.outError("Couldn't find the caster of the single target aura, may crash later!");
4122 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
4123 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
4125 m_modAuras
[Aur
->GetModifier()->m_auraname
].remove(Aur
);
4129 Aur
->SetRemoveMode(mode
);
4130 // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura
4131 // remove aura from list before to prevent deleting it before
4133 ++m_removedAuras
; // internal count used by unit update
4135 // Statue unsummoned at aura remove
4136 Totem
* statue
= NULL
;
4137 bool caster_channeled
= false;
4138 if(IsChanneledSpell(AurSpellInfo
))
4140 if(!caster
) // can be already located for IsSingleTargetSpell case
4141 caster
= Aur
->GetCaster();
4145 if(caster
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)caster
)->isTotem() && ((Totem
*)caster
)->GetTotemType()==TOTEM_STATUE
)
4146 statue
= ((Totem
*)caster
);
4148 caster_channeled
= caster
==this;
4152 sLog
.outDebug("Aura %u now is remove mode %d",Aur
->GetModifier()->m_auraname
, mode
);
4153 Aur
->ApplyModifier(false,true);
4157 if(caster_channeled
)
4158 RemoveAurasAtChanneledTarget (AurSpellInfo
);
4163 // only way correctly remove all auras from list
4164 if( m_Auras
.empty() )
4167 i
= m_Auras
.begin();
4170 void Unit::RemoveAllAuras()
4172 while (!m_Auras
.empty())
4174 AuraMap::iterator iter
= m_Auras
.begin();
4179 void Unit::RemoveArenaAuras(bool onleave
)
4181 // in join, remove positive buffs, on end, remove negative
4182 // used to remove positive visible auras in arenas
4183 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4185 if ( !(iter
->second
->GetSpellProto()->AttributesEx4
& (1<<21)) // don't remove stances, shadowform, pally/hunter auras
4186 && !iter
->second
->IsPassive() // don't remove passive auras
4187 && (!(iter
->second
->GetSpellProto()->Attributes
& SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY
) || !(iter
->second
->GetSpellProto()->Attributes
& SPELL_ATTR_UNK8
)) // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable)
4188 && (iter
->second
->IsPositive() ^ onleave
)) // remove positive buffs on enter, negative buffs on leave
4195 void Unit::RemoveAllAurasOnDeath()
4197 // used just after dieing to remove all visible auras
4198 // and disable the mods for the passive ones
4199 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
4201 if (!iter
->second
->IsPassive() && !iter
->second
->IsDeathPersistent())
4202 RemoveAura(iter
, AURA_REMOVE_BY_DEATH
);
4208 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
4210 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4211 if (iter
!= m_Auras
.end())
4213 if (iter
->second
->GetAuraDuration() < delaytime
)
4214 iter
->second
->SetAuraDuration(0);
4216 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
4217 iter
->second
->SendAuraUpdate(false);
4218 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
4222 void Unit::_RemoveAllAuraMods()
4224 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4226 (*i
).second
->ApplyModifier(false);
4230 void Unit::_ApplyAllAuraMods()
4232 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
4234 (*i
).second
->ApplyModifier(true);
4238 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
4240 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
4241 if (iter
!= m_Auras
.end())
4242 return iter
->second
;
4246 void Unit::AddDynObject(DynamicObject
* dynObj
)
4248 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
4251 void Unit::RemoveDynObject(uint32 spellid
)
4253 if(m_dynObjGUIDs
.empty())
4255 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4257 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4260 i
= m_dynObjGUIDs
.erase(i
);
4262 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
4265 i
= m_dynObjGUIDs
.erase(i
);
4272 void Unit::RemoveAllDynObjects()
4274 while(!m_dynObjGUIDs
.empty())
4276 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4279 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
4283 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
4285 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4287 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4290 i
= m_dynObjGUIDs
.erase(i
);
4294 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
4301 DynamicObject
* Unit::GetDynObject(uint32 spellId
)
4303 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
4305 DynamicObject
* dynObj
= ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
4308 i
= m_dynObjGUIDs
.erase(i
);
4312 if (dynObj
->GetSpellId() == spellId
)
4319 void Unit::AddGameObject(GameObject
* gameObj
)
4321 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
4322 m_gameObj
.push_back(gameObj
);
4323 gameObj
->SetOwnerGUID(GetGUID());
4326 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
4328 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
4330 // GO created by some spell
4331 if ( GetTypeId()==TYPEID_PLAYER
&& gameObj
->GetSpellId() )
4333 SpellEntry
const* createBySpell
= sSpellStore
.LookupEntry(gameObj
->GetSpellId());
4334 // Need activate spell use for owner
4335 if (createBySpell
&& createBySpell
->Attributes
& SPELL_ATTR_DISABLED_WHILE_ACTIVE
)
4336 ((Player
*)this)->SendCooldownEvent(createBySpell
);
4338 gameObj
->SetOwnerGUID(0);
4339 m_gameObj
.remove(gameObj
);
4342 gameObj
->SetRespawnTime(0);
4347 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
4349 if(m_gameObj
.empty())
4351 std::list
<GameObject
*>::iterator i
, next
;
4352 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
4355 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
4357 (*i
)->SetOwnerGUID(0);
4360 (*i
)->SetRespawnTime(0);
4364 next
= m_gameObj
.erase(i
);
4371 void Unit::RemoveAllGameObjects()
4373 // remove references to unit
4374 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
4376 (*i
)->SetOwnerGUID(0);
4377 (*i
)->SetRespawnTime(0);
4379 i
= m_gameObj
.erase(i
);
4383 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchoolMask damageSchoolMask
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
4385 sLog
.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
4386 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
4387 data
.append(target
->GetPackGUID());
4388 data
.append(GetPackGUID());
4389 data
<< uint32(SpellID
);
4390 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
4391 data
<< uint32(0); // wotlk
4392 data
<< uint8(damageSchoolMask
); // spell school
4393 data
<< uint32(AbsorbedDamage
); // AbsorbedDamage
4394 data
<< uint32(Resist
); // resist
4395 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
4396 data
<< uint8(0); // unk isFromAura
4397 data
<< uint32(Blocked
); // blocked
4398 data
<< uint32(CriticalHit
? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
4399 data
<< uint8(0); // isDebug?
4400 SendMessageToSet( &data
, true );
4403 void Unit::SendSpellMiss(Unit
*target
, uint32 spellID
, SpellMissInfo missInfo
)
4405 WorldPacket
data(SMSG_SPELLLOGMISS
, (4+8+1+4+8+1));
4406 data
<< uint32(spellID
);
4407 data
<< uint64(GetGUID());
4408 data
<< uint8(0); // can be 0 or 1
4409 data
<< uint32(1); // target count
4410 // for(i = 0; i < target count; ++i)
4411 data
<< uint64(target
->GetGUID()); // target GUID
4412 data
<< uint8(missInfo
);
4414 SendMessageToSet(&data
, true);
4417 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchoolMask damageSchoolMask
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, VictimState TargetState
, uint32 BlockedAmount
)
4419 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
4421 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
4422 data
<< uint32(HitInfo
); // flags
4423 data
.append(GetPackGUID());
4424 data
.append(target
->GetPackGUID());
4425 data
<< uint32(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);// damage
4426 data
<< uint32(0); // overkill value
4428 data
<< (uint8
)SwingType
; // count?
4430 // for(i = 0; i < SwingType; ++i)
4431 data
<< (uint32
)damageSchoolMask
;
4432 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4433 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
4436 if(HitInfo
& (HITINFO_ABSORB
| HITINFO_ABSORB2
))
4438 // for(i = 0; i < SwingType; ++i)
4439 data
<< uint32(AbsorbDamage
);
4443 if(HitInfo
& (HITINFO_RESIST
| HITINFO_RESIST2
))
4445 // for(i = 0; i < SwingType; ++i)
4446 data
<< uint32(Resist
);
4450 data
<< (uint8
)TargetState
;
4454 if(HitInfo
& HITINFO_BLOCK
)
4456 data
<< uint32(BlockedAmount
);
4459 if(HitInfo
& HITINFO_UNK3
)
4464 if(HitInfo
& HITINFO_UNK1
)
4475 for(uint8 i
= 0; i
< 5; ++i
)
4483 SendMessageToSet( &data
, true );
4486 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
4488 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
4490 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
4492 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
4493 // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect
4494 // That is the question though if it's fully correct
4495 if(procSpell
&& !isTriggeredSpell
)
4497 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
4499 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
4500 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
4501 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
4502 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
4503 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
4505 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
4507 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
4508 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
4509 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
4510 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
4511 attType
= RANGED_ATTACK
;
4514 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
4515 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
4517 // Not much to do if no flags are set.
4520 // 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
4521 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcEffectAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4522 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcCastAuraTypes
,attType
, procSpell
, damage
, damageSchoolMask
);
4525 // Now go on with a victim's events'n'auras
4526 // Not much to do if no flags are set or there is no victim
4527 if(pVictim
&& pVictim
->isAlive() && procVictim
)
4529 // 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
4530 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcEffectAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4531 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcCastAuraTypes
,attType
,procSpell
, damage
, damageSchoolMask
);
4535 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, SpellSchoolMask damageSchoolMask
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
4540 uint32 procAttacker
= PROC_FLAG_NONE
;
4541 uint32 procVictim
= PROC_FLAG_NONE
;
4545 case MELEE_HIT_EVADE
:
4547 case MELEE_HIT_MISS
:
4548 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4550 procAttacker
= PROC_FLAG_MISS
;
4553 case MELEE_HIT_BLOCK_CRIT
:
4554 case MELEE_HIT_CRIT
:
4555 if(spellCasted
&& attType
== BASE_ATTACK
)
4557 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
4558 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
4559 if ( outcome
== MELEE_HIT_BLOCK_CRIT
)
4561 procVictim
|= PROC_FLAG_BLOCK
;
4562 procAttacker
|= PROC_FLAG_TARGET_BLOCK
;
4565 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4567 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4568 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4572 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4573 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4576 case MELEE_HIT_PARRY
:
4577 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4578 procVictim
= PROC_FLAG_PARRY
;
4580 case MELEE_HIT_BLOCK
:
4581 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
4582 procVictim
= PROC_FLAG_BLOCK
;
4584 case MELEE_HIT_DODGE
:
4585 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
4586 procVictim
= PROC_FLAG_DODGE
;
4588 case MELEE_HIT_CRUSHING
:
4589 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4591 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
4592 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
4596 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
4597 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
4601 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
4603 procAttacker
= PROC_FLAG_HIT_MELEE
;
4604 procVictim
= PROC_FLAG_STRUCK_MELEE
;
4608 procAttacker
= PROC_FLAG_HIT_RANGED
;
4609 procVictim
= PROC_FLAG_STRUCK_RANGED
;
4615 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
4617 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
4618 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, damageSchoolMask
, spellCasted
, isTriggeredSpell
, attType
);
4621 bool Unit::HandleHasteAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * /*procSpell*/, uint32
/*procFlag*/, uint32 cooldown
)
4623 SpellEntry
const *hasteSpell
= triggeredByAura
->GetSpellProto();
4625 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4626 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4628 uint32 triggered_spell_id
= 0;
4629 Unit
* target
= pVictim
;
4630 int32 basepoints0
= 0;
4632 switch(hasteSpell
->SpellFamilyName
)
4634 case SPELLFAMILY_ROGUE
:
4636 switch(hasteSpell
->Id
)
4642 target
= SelectNearbyTarget();
4645 basepoints0
= damage
;
4646 triggered_spell_id
= 22482;
4654 // processed charge only counting case
4655 if(!triggered_spell_id
)
4658 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
4662 sLog
.outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u",hasteSpell
->Id
,triggered_spell_id
);
4667 if(!target
|| target
!=this && !target
->isAlive())
4670 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
4674 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
4676 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
4678 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
4679 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
4684 bool Unit::HandleDummyAuraProc(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
, uint32 cooldown
)
4686 SpellEntry
const *dummySpell
= triggeredByAura
->GetSpellProto ();
4687 uint32 effIndex
= triggeredByAura
->GetEffIndex ();
4689 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
4690 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
4692 uint32 triggered_spell_id
= 0;
4693 Unit
* target
= pVictim
;
4694 int32 basepoints0
= 0;
4696 switch(dummySpell
->SpellFamilyName
)
4698 case SPELLFAMILY_GENERIC
:
4700 switch (dummySpell
->Id
)
4706 // prevent damage back from weapon special attacks
4707 if (!procSpell
|| procSpell
->DmgClass
!= SPELL_DAMAGE_CLASS_MAGIC
)
4710 // return damage % to attacker but < 50% own total health
4711 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*int32(damage
)/100;
4712 if(basepoints0
> GetMaxHealth()/2)
4713 basepoints0
= GetMaxHealth()/2;
4715 triggered_spell_id
= 25997;
4723 // prevent chain of triggered spell from same triggered spell
4724 if(procSpell
&& procSpell
->Id
==26654)
4727 target
= SelectNearbyTarget();
4731 triggered_spell_id
= 26654;
4737 if (!procSpell
|| procSpell
->Id
== 24659)
4739 // Need remove one 24659 aura
4740 RemoveSingleAuraFromStack(24659, 0);
4741 RemoveSingleAuraFromStack(24659, 1);
4744 // Restless Strength
4747 // Need remove one 24662 aura
4748 RemoveSingleAuraFromStack(24662, 0);
4751 // Adaptive Warding (Frostfire Regalia set)
4759 AuraList
const& mRegenInterupt
= GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
);
4760 for(AuraList::const_iterator iter
= mRegenInterupt
.begin(); iter
!= mRegenInterupt
.end(); ++iter
)
4762 if(SpellEntry
const* iterSpellProto
= (*iter
)->GetSpellProto())
4764 if(iterSpellProto
->SpellFamilyName
==SPELLFAMILY_MAGE
&& (iterSpellProto
->SpellFamilyFlags
& 0x10000000))
4774 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4776 case SPELL_SCHOOL_NORMAL
:
4777 case SPELL_SCHOOL_HOLY
:
4778 return false; // ignored
4779 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 28765; break;
4780 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 28768; break;
4781 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 28766; break;
4782 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 28769; break;
4783 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 28770; break;
4791 // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
4799 for(int j
= 0; j
< 3; ++j
)
4801 if(procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
4810 switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell
)))
4812 case SPELL_SCHOOL_NORMAL
:
4813 return false; // ignore
4814 case SPELL_SCHOOL_HOLY
: triggered_spell_id
= 27536; break;
4815 case SPELL_SCHOOL_FIRE
: triggered_spell_id
= 27533; break;
4816 case SPELL_SCHOOL_NATURE
: triggered_spell_id
= 27538; break;
4817 case SPELL_SCHOOL_FROST
: triggered_spell_id
= 27534; break;
4818 case SPELL_SCHOOL_SHADOW
: triggered_spell_id
= 27535; break;
4819 case SPELL_SCHOOL_ARCANE
: triggered_spell_id
= 27540; break;
4827 // Mana Leech (Passive) (Priest Pet Aura)
4831 target
= GetOwner();
4835 basepoints0
= int32(damage
* 2.5f
); // manaregen
4836 triggered_spell_id
= 34650;
4842 // Cast finish spell at last charge
4843 if (triggeredByAura
->m_procCharges
> 1)
4847 triggered_spell_id
= 33494;
4850 // Twisted Reflection (boss spell)
4852 triggered_spell_id
= 21064;
4854 // Vampiric Aura (boss spell)
4857 basepoints0
= 3 * damage
; // 300%
4858 if (basepoints0
< 0)
4861 triggered_spell_id
= 31285;
4865 // Aura of Madness (Darkmoon Card: Madness trinket)
4866 //=====================================================
4867 // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
4868 // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
4869 // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
4870 // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4871 // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
4872 // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
4873 // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
4874 // 41011 Martyr Complex: +35 stamina (All classes)
4875 // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4876 // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
4879 if(GetTypeId() != TYPEID_PLAYER
)
4882 // Select class defined buff
4885 case CLASS_PALADIN
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4886 case CLASS_DRUID
: // 39511,40997,40998,40999,41002,41005,41009,41011,41409
4888 uint32 RandomSpell
[]={39511,40997,40998,40999,41002,41005,41009,41011,41409};
4889 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4892 case CLASS_ROGUE
: // 39511,40997,40998,41002,41005,41011
4893 case CLASS_WARRIOR
: // 39511,40997,40998,41002,41005,41011
4895 uint32 RandomSpell
[]={39511,40997,40998,41002,41005,41011};
4896 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4899 case CLASS_PRIEST
: // 40999,41002,41005,41009,41011,41406,41409
4900 case CLASS_SHAMAN
: // 40999,41002,41005,41009,41011,41406,41409
4901 case CLASS_MAGE
: // 40999,41002,41005,41009,41011,41406,41409
4902 case CLASS_WARLOCK
: // 40999,41002,41005,41009,41011,41406,41409
4904 uint32 RandomSpell
[]={40999,41002,41005,41009,41011,41406,41409};
4905 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4908 case CLASS_HUNTER
: // 40997,40999,41002,41005,41009,41011,41406,41409
4910 uint32 RandomSpell
[]={40997,40999,41002,41005,41009,41011,41406,41409};
4911 triggered_spell_id
= RandomSpell
[ irand(0, sizeof(RandomSpell
)/sizeof(uint32
) - 1) ];
4919 if (roll_chance_i(10))
4920 ((Player
*)this)->Say("This is Madness!", LANG_UNIVERSAL
);
4924 // TODO: need find item for aura and triggered spells
4925 // Sunwell Exalted Caster Neck (??? neck)
4926 // cast ??? Light's Wrath if Exalted by Aldor
4927 // cast ??? Arcane Bolt if Exalted by Scryers*/
4929 return false; // disable for while
4932 if(GetTypeId() != TYPEID_PLAYER)
4935 // Get Aldor reputation rank
4936 if (((Player *)this)->GetReputationRank(932) == REP_EXALTED)
4939 triggered_spell_id = ???
4942 // Get Scryers reputation rank
4943 if (((Player *)this)->GetReputationRank(934) == REP_EXALTED)
4945 triggered_spell_id = ???
4950 // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
4951 // cast 45479 Light's Wrath if Exalted by Aldor
4952 // cast 45429 Arcane Bolt if Exalted by Scryers
4955 if(GetTypeId() != TYPEID_PLAYER
)
4958 // Get Aldor reputation rank
4959 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4962 triggered_spell_id
= 45479;
4965 // Get Scryers reputation rank
4966 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4968 triggered_spell_id
= 45429;
4973 // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
4974 // cast 45480 Light's Strength if Exalted by Aldor
4975 // cast 45428 Arcane Strike if Exalted by Scryers
4978 if(GetTypeId() != TYPEID_PLAYER
)
4981 // Get Aldor reputation rank
4982 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
4985 triggered_spell_id
= 45480;
4988 // Get Scryers reputation rank
4989 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
4991 triggered_spell_id
= 45428;
4996 // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
4997 // cast 45431 Arcane Insight if Exalted by Aldor
4998 // cast 45432 Light's Ward if Exalted by Scryers
5001 if(GetTypeId() != TYPEID_PLAYER
)
5004 // Get Aldor reputation rank
5005 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
5008 triggered_spell_id
= 45432;
5011 // Get Scryers reputation rank
5012 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5015 triggered_spell_id
= 45431;
5020 // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
5021 // cast 45478 Light's Salvation if Exalted by Aldor
5022 // cast 45430 Arcane Surge if Exalted by Scryers
5025 if(GetTypeId() != TYPEID_PLAYER
)
5028 // Get Aldor reputation rank
5029 if (((Player
*)this)->GetReputationRank(932) == REP_EXALTED
)
5032 triggered_spell_id
= 45478;
5035 // Get Scryers reputation rank
5036 if (((Player
*)this)->GetReputationRank(934) == REP_EXALTED
)
5038 triggered_spell_id
= 45430;
5046 case SPELLFAMILY_MAGE
:
5049 if (dummySpell
->SpellIconID
== 459) // only this spell have SpellIconID == 459 and dummy aura
5051 if (getPowerType() != POWER_MANA
)
5055 basepoints0
= (triggeredByAura
->GetModifier()->m_amount
* GetMaxPower(POWER_MANA
) / 100);
5057 triggered_spell_id
= 29442;
5060 // Master of Elements
5061 if (dummySpell
->SpellIconID
== 1920)
5067 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5068 if( basepoints0
<=0 )
5072 triggered_spell_id
= 29077;
5075 switch(dummySpell
->Id
)
5084 switch (dummySpell
->Id
)
5086 case 11119: basepoints0
= int32(0.04f
*damage
); break;
5087 case 11120: basepoints0
= int32(0.08f
*damage
); break;
5088 case 12846: basepoints0
= int32(0.12f
*damage
); break;
5089 case 12847: basepoints0
= int32(0.16f
*damage
); break;
5090 case 12848: basepoints0
= int32(0.20f
*damage
); break;
5092 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
5096 triggered_spell_id
= 12654;
5102 //last charge and crit
5103 if( triggeredByAura
->m_procCharges
<= 1 && (procFlag
& PROC_FLAG_CRIT_SPELL
) )
5105 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
5106 return true; // charge counting (will removed)
5109 CastSpell(this, 28682, true, castItem
, triggeredByAura
);
5110 return(procFlag
& PROC_FLAG_CRIT_SPELL
);// charge update only at crit hits, no hidden cooldowns
5115 case SPELLFAMILY_WARRIOR
:
5118 if(dummySpell
->SpellFamilyFlags
==0x0000000800000000LL
)
5120 // check attack comes not from behind
5121 if (!HasInArc(M_PI
, pVictim
))
5124 triggered_spell_id
= 22858;
5129 case SPELLFAMILY_WARLOCK
:
5131 // Seed of Corruption
5132 if (dummySpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5134 Modifier
* mod
= triggeredByAura
->GetModifier();
5135 // if damage is more than need or target die from damage deal finish spell
5136 // FIX ME: not triggered currently at death
5137 if( mod
->m_amount
<= damage
|| GetHealth() <= damage
)
5139 // remember guid before aura delete
5140 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5142 // Remove aura (before cast for prevent infinite loop handlers)
5143 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5145 // Cast finish spell (triggeredByAura already not exist!)
5146 CastSpell(this, 27285, true, castItem
, NULL
, casterGuid
);
5147 return true; // no hidden cooldown
5151 mod
->m_amount
-=damage
;
5154 // Seed of Corruption (Mobs cast) - no die req
5155 if (dummySpell
->SpellFamilyFlags
== 0x00LL
&& dummySpell
->SpellIconID
== 1932)
5157 Modifier
* mod
= triggeredByAura
->GetModifier();
5158 // if damage is more than need deal finish spell
5159 if( mod
->m_amount
<= damage
)
5161 // remember guid before aura delete
5162 uint64 casterGuid
= triggeredByAura
->GetCasterGUID();
5164 // Remove aura (before cast for prevent infinite loop handlers)
5165 RemoveAurasDueToSpell(triggeredByAura
->GetId());
5167 // Cast finish spell (triggeredByAura already not exist!)
5168 CastSpell(this, 32865, true, castItem
, NULL
, casterGuid
);
5169 return true; // no hidden cooldown
5172 mod
->m_amount
-=damage
;
5175 switch(dummySpell
->Id
)
5182 triggered_spell_id
= 17941;
5191 basepoints0
= int32(damage
*triggeredByAura
->GetModifier()->m_amount
/100);
5193 triggered_spell_id
= 30294;
5196 // Shadowflame (Voidheart Raiment set bonus)
5199 triggered_spell_id
= 37379;
5202 // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
5210 basepoints0
= damage
* triggeredByAura
->GetModifier()->m_amount
/100;
5211 triggered_spell_id
= 37382;
5214 // Shadowflame Hellfire (Voidheart Raiment set bonus)
5217 triggered_spell_id
= 37378;
5223 case SPELLFAMILY_PRIEST
:
5226 if( dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5228 if(!pVictim
|| !pVictim
->isAlive())
5231 // pVictim is caster of aura
5232 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5236 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5237 pVictim
->CastCustomSpell(pVictim
,34919,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5238 return true; // no hidden cooldown
5240 switch(dummySpell
->Id
)
5245 if(!pVictim
|| !pVictim
->isAlive())
5248 // pVictim is caster of aura
5249 if(triggeredByAura
->GetCasterGUID() != pVictim
->GetGUID())
5253 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5254 pVictim
->CastCustomSpell(pVictim
,15290,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5255 return true; // no hidden cooldown
5257 // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
5260 // Shadow Word: Pain
5261 if( procSpell
->SpellFamilyFlags
& 0x0000000000008000LL
)
5262 triggered_spell_id
= 40441;
5264 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5265 triggered_spell_id
= 40440;
5272 // Oracle Healing Bonus ("Garments of the Oracle" set)
5276 basepoints0
= int32(damage
* 10/100);
5278 triggered_spell_id
= 26170;
5281 // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
5284 if(!procSpell
|| (GetSpellSchoolMask(procSpell
) & (SPELL_SCHOOL_MASK_FROST
| SPELL_SCHOOL_MASK_SHADOW
))==0 )
5288 basepoints0
= int32(damage
* 2 / 100);
5290 triggered_spell_id
= 39373;
5293 // Vestments of Faith (Priest Tier 3) - 4 pieces bonus
5296 triggered_spell_id
= 28810;
5302 case SPELLFAMILY_DRUID
:
5304 switch(dummySpell
->Id
)
5306 // Healing Touch (Dreamwalker Raiment set)
5310 basepoints0
= int32(procSpell
->manaCost
* 30 / 100);
5312 triggered_spell_id
= 28742;
5315 // Healing Touch Refund (Idol of Longevity trinket)
5319 triggered_spell_id
= 28848;
5322 // Mana Restore (Malorne Raiment set / Malorne Regalia set)
5327 triggered_spell_id
= 37238;
5330 // Druid Tier 6 Trinket
5336 if( procSpell
->SpellFamilyFlags
& 0x0000000000000004LL
)
5338 triggered_spell_id
= 40445;
5342 else if( procSpell
->SpellFamilyFlags
& 0x0000000000000010LL
)
5344 triggered_spell_id
= 40446;
5347 // Mangle (cat/bear)
5348 else if( procSpell
->SpellFamilyFlags
& 0x0000044000000000LL
)
5350 triggered_spell_id
= 40452;
5356 if (!roll_chance_f(chance
))
5365 // Deadly Interrupt Effect
5366 triggered_spell_id
= 32747;
5372 case SPELLFAMILY_ROGUE
:
5374 switch(dummySpell
->Id
)
5376 // Deadly Throw Interrupt
5379 // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
5383 triggered_spell_id
= 32747;
5388 if( dummySpell
->SpellIconID
== 2116 )
5393 // only rogue's finishing moves (maybe need additional checks)
5394 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
5395 (procSpell
->SpellFamilyFlags
& SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE
) == 0)
5399 basepoints0
= procSpell
->manaCost
* triggeredByAura
->GetModifier()->m_amount
/100;
5400 if(basepoints0
<= 0)
5404 triggered_spell_id
= 31663;
5409 case SPELLFAMILY_HUNTER
:
5411 // Thrill of the Hunt
5412 if ( dummySpell
->SpellIconID
== 2236 )
5418 basepoints0
= procSpell
->manaCost
* 40/100;
5419 if(basepoints0
<= 0)
5423 triggered_spell_id
= 34720;
5428 case SPELLFAMILY_PALADIN
:
5430 // Seal of Righteousness - melee proc dummy
5431 if (dummySpell
->SpellFamilyFlags
&0x000000008000000LL
&& triggeredByAura
->GetEffIndex()==0)
5433 if(GetTypeId() != TYPEID_PLAYER
)
5437 switch (triggeredByAura
->GetId())
5439 case 21084: spellId
= 25742; break; // Rank 1
5440 case 20287: spellId
= 25740; break; // Rank 2
5441 case 20288: spellId
= 25739; break; // Rank 3
5442 case 20289: spellId
= 25738; break; // Rank 4
5443 case 20290: spellId
= 25737; break; // Rank 5
5444 case 20291: spellId
= 25736; break; // Rank 6
5445 case 20292: spellId
= 25735; break; // Rank 7
5446 case 20293: spellId
= 25713; break; // Rank 8
5447 case 27155: spellId
= 27156; break; // Rank 9
5449 sLog
.outError("Unit::HandleDummyAuraProc: non handled possibly SoR (Id = %u)", triggeredByAura
->GetId());
5452 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
5453 float speed
= (item
? item
->GetProto()->Delay
: BASE_ATTACK_TIME
)/1000.0f
;
5455 float damageBasePoints
;
5456 if(item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
5458 damageBasePoints
=1.20f
*triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
+ 1;
5460 // one hand weapon/no weapon
5461 damageBasePoints
=0.85f
*ceil(triggeredByAura
->GetModifier()->m_amount
* 1.2f
* 1.03f
* speed
/100.0f
) - 1;
5463 int32 damagePoint
= int32(damageBasePoints
+ 0.03f
* (GetWeaponDamageRange(BASE_ATTACK
,MINDAMAGE
)+GetWeaponDamageRange(BASE_ATTACK
,MAXDAMAGE
))/2.0f
) + 1;
5465 // apply damage bonuses manually
5466 if(damagePoint
>= 0)
5467 damagePoint
= SpellDamageBonus(pVictim
, dummySpell
, damagePoint
, SPELL_DIRECT_DAMAGE
);
5469 CastCustomSpell(pVictim
,spellId
,&damagePoint
,NULL
,NULL
,true,NULL
, triggeredByAura
);
5470 return true; // no hidden cooldown
5472 // Seal of Blood do damage trigger
5473 if(dummySpell
->SpellFamilyFlags
& 0x0000040000000000LL
)
5475 switch(triggeredByAura
->GetEffIndex())
5478 // prevent chain triggering
5479 if(procSpell
&& procSpell
->Id
==31893 )
5482 triggered_spell_id
= 31893;
5487 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* damage
/ 100;
5489 triggered_spell_id
= 32221;
5495 switch(dummySpell
->Id
)
5497 // Holy Power (Redemption Armor set)
5503 // Set class defined buff
5504 switch (pVictim
->getClass())
5510 triggered_spell_id
= 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5514 triggered_spell_id
= 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5518 triggered_spell_id
= 28791; // Increases the friendly target's attack power by $s1 for $d.
5521 triggered_spell_id
= 28790; // Increases the friendly target's armor
5531 if(effIndex
!= 0) // effect 1,2 used by seal unleashing code
5534 triggered_spell_id
= 31803;
5541 // if healed by another unit (pVictim)
5546 basepoints0
= triggeredByAura
->GetModifier()->m_amount
*damage
/100;
5548 triggered_spell_id
= 31786;
5551 // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
5559 // Flash of light/Holy light
5560 if( procSpell
->SpellFamilyFlags
& 0x00000000C0000000LL
)
5562 triggered_spell_id
= 40471;
5566 else if( procSpell
->SpellFamilyFlags
& 0x0000000000800000LL
)
5568 triggered_spell_id
= 40472;
5574 if (!roll_chance_f(chance
))
5582 case SPELLFAMILY_SHAMAN
:
5584 switch(dummySpell
->Id
)
5586 // Totemic Power (The Earthshatterer set)
5592 // Set class defined buff
5593 switch (pVictim
->getClass())
5599 triggered_spell_id
= 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
5603 triggered_spell_id
= 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
5607 triggered_spell_id
= 28826; // Increases the friendly target's attack power by $s1 for $d.
5610 triggered_spell_id
= 28827; // Increases the friendly target's armor
5617 // Lesser Healing Wave (Totem of Flowing Water Relic)
5621 triggered_spell_id
= 28850;
5624 // Windfury Weapon (Passive) 1-5 Ranks
5627 if(GetTypeId()!=TYPEID_PLAYER
)
5630 if(!castItem
|| !castItem
->IsEquipped())
5633 // custom cooldown processing case
5634 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5638 switch (castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)))
5640 case 283: spellId
= 33757; break; //1 Rank
5641 case 284: spellId
= 33756; break; //2 Rank
5642 case 525: spellId
= 33755; break; //3 Rank
5643 case 1669:spellId
= 33754; break; //4 Rank
5644 case 2636:spellId
= 33727; break; //5 Rank
5647 sLog
.outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
5648 castItem
->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT
)),dummySpell
->Id
);
5653 SpellEntry
const* windfurySpellEntry
= sSpellStore
.LookupEntry(spellId
);
5654 if(!windfurySpellEntry
)
5656 sLog
.outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)",spellId
);
5660 int32 extra_attack_power
= CalculateSpellDamage(windfurySpellEntry
,0,windfurySpellEntry
->EffectBasePoints
[0],pVictim
);
5663 if ( castItem
->GetSlot() == EQUIPMENT_SLOT_OFFHAND
)
5665 // Value gained from additional AP
5666 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(OFF_ATTACK
)/1000/2);
5667 triggered_spell_id
= 33750;
5672 // Value gained from additional AP
5673 basepoints0
= int32(extra_attack_power
/14.0f
* GetAttackTime(BASE_ATTACK
)/1000);
5674 triggered_spell_id
= 25504;
5677 // apply cooldown before cast to prevent processing itself
5679 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5682 for ( uint32 i
= 0; i
<2; ++i
)
5683 CastCustomSpell(pVictim
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5687 // Shaman Tier 6 Trinket
5694 if (procSpell
->SpellFamilyFlags
& 0x0000000000000001LL
)
5696 triggered_spell_id
= 40465; // Lightning Bolt
5699 else if (procSpell
->SpellFamilyFlags
& 0x0000000000000080LL
)
5701 triggered_spell_id
= 40465; // Lesser Healing Wave
5704 else if (procSpell
->SpellFamilyFlags
& 0x0000001000000000LL
)
5706 triggered_spell_id
= 40466; // Stormstrike
5712 if (!roll_chance_f(chance
))
5721 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
5723 if(GetTypeId() != TYPEID_PLAYER
)
5727 basepoints0
= triggeredByAura
->GetModifier()->m_amount
;
5729 triggered_spell_id
= 379;
5732 // Lightning Overload
5733 if (dummySpell
->SpellIconID
== 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
5735 if(!procSpell
|| GetTypeId() != TYPEID_PLAYER
|| !pVictim
)
5738 // custom cooldown processing case
5739 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(dummySpell
->Id
))
5743 // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
5744 switch (procSpell
->Id
)
5747 case 403: spellId
= 45284; break; // Rank 1
5748 case 529: spellId
= 45286; break; // Rank 2
5749 case 548: spellId
= 45287; break; // Rank 3
5750 case 915: spellId
= 45288; break; // Rank 4
5751 case 943: spellId
= 45289; break; // Rank 5
5752 case 6041: spellId
= 45290; break; // Rank 6
5753 case 10391: spellId
= 45291; break; // Rank 7
5754 case 10392: spellId
= 45292; break; // Rank 8
5755 case 15207: spellId
= 45293; break; // Rank 9
5756 case 15208: spellId
= 45294; break; // Rank 10
5757 case 25448: spellId
= 45295; break; // Rank 11
5758 case 25449: spellId
= 45296; break; // Rank 12
5760 case 421: spellId
= 45297; break; // Rank 1
5761 case 930: spellId
= 45298; break; // Rank 2
5762 case 2860: spellId
= 45299; break; // Rank 3
5763 case 10605: spellId
= 45300; break; // Rank 4
5764 case 25439: spellId
= 45301; break; // Rank 5
5765 case 25442: spellId
= 45302; break; // Rank 6
5767 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell
->Id
);
5770 // No thread generated mod
5771 SpellModifier
*mod
= new SpellModifier
;
5772 mod
->op
= SPELLMOD_THREAT
;
5774 mod
->type
= SPELLMOD_PCT
;
5775 mod
->spellId
= dummySpell
->Id
;
5776 mod
->mask
= 0x0000000000000003LL
;
5778 ((Player
*)this)->AddSpellMod(mod
, true);
5780 // Remove cooldown (Chain Lightning - have Category Recovery time)
5781 if (procSpell
->SpellFamilyFlags
& 0x0000000000000002LL
)
5782 ((Player
*)this)->RemoveSpellCooldown(spellId
);
5784 // Hmmm.. in most case spells already set half basepoints but...
5785 // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level
5787 // 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.
5788 // So - no add changes :)
5789 CastSpell(pVictim
, spellId
, true, castItem
, triggeredByAura
);
5791 ((Player
*)this)->AddSpellMod(mod
, false);
5793 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5794 ((Player
*)this)->AddSpellCooldown(dummySpell
->Id
,0,time(NULL
) + cooldown
);
5804 // processed charge only counting case
5805 if(!triggered_spell_id
)
5808 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
5812 sLog
.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell
->Id
,triggered_spell_id
);
5817 if(!target
|| target
!=this && !target
->isAlive())
5820 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
5824 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
5826 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
5828 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
5829 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
5834 bool Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
,WeaponAttackType attackType
, uint32 cooldown
)
5836 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
5838 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
5839 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
5841 uint32 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
5842 Unit
* target
= !(procFlags
& PROC_FLAG_HEAL
) && IsPositiveSpell(triggered_spell_id
) ? this : pVictim
;
5843 int32 basepoints0
= 0;
5845 switch(auraSpellInfo
->SpellFamilyName
)
5847 case SPELLFAMILY_GENERIC
:
5849 switch(auraSpellInfo
->Id
)
5851 // Aegis of Preservation
5853 //Aegis Heal (instead non-existed triggered spell)
5854 triggered_spell_id
= 23781;
5857 // Elune's Touch (moonkin mana restore)
5860 // Elune's Touch (instead non-existed triggered spell)
5861 triggered_spell_id
= 33926;
5862 basepoints0
= int32(0.3f
* GetTotalAttackPowerValue(BASE_ATTACK
));
5869 // only for cast with mana price
5870 if(!procSpell
|| procSpell
->powerType
!=POWER_MANA
|| procSpell
->manaCost
==0 && procSpell
->ManaCostPercentage
==0 && procSpell
->manaCostPerlevel
==0)
5872 break; // fall through to normal cast
5877 // at melee hit call std triggered spell
5878 if(procFlags
& PROC_FLAG_HIT_MELEE
)
5879 break; // fall through to normal cast
5881 // Mark of Conquest - else (at range hit) called custom case
5882 triggered_spell_id
= 39557;
5888 return true; // nothing to do
5889 // Forgotten Knowledge (Blade of Wizardry)
5891 // only for harmful enemy targeted spell
5892 if(!pVictim
|| pVictim
==this || !procSpell
|| IsPositiveSpell(procSpell
->Id
))
5894 break; // fall through to normal cast
5895 // Aura of Wrath (Darkmoon Card: Wrath trinket bonus)
5898 // proc only at non-crit hits
5899 if(procFlags
& (PROC_FLAG_CRIT_MELEE
|PROC_FLAG_CRIT_RANGED
|PROC_FLAG_CRIT_SPELL
))
5901 break; // fall through to normal cast
5903 // Augment Pain (Timbal's Focusing Crystal trinket bonus)
5909 //only periodic damage can trigger spell
5911 for(int j
= 0; j
< 3; ++j
)
5913 if( procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE
||
5914 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT
||
5915 procSpell
->EffectApplyAuraName
[j
]==SPELL_AURA_PERIODIC_LEECH
)
5924 break; // fall through to normal cast
5926 // Evasive Maneuvers (Commendation of Kael'thas)
5929 // damage taken that reduces below 35% health
5930 // does NOT mean you must have been >= 35% before
5931 if (int32(GetHealth())-int32(damage
) >= int32(GetMaxHealth()*0.35f
))
5933 break; // fall through to normal cast
5937 switch(triggered_spell_id
)
5942 // applied only for main target
5943 if(!pVictim
|| pVictim
!= getVictim())
5946 // continue normal case
5949 // Shamanistic Rage triggered spell
5951 basepoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100);
5956 case SPELLFAMILY_MAGE
:
5958 switch(auraSpellInfo
->SpellIconID
)
5962 //Blazing Speed (instead non-existed triggered spell)
5963 triggered_spell_id
= 31643;
5967 switch(auraSpellInfo
->Id
)
5969 // Persistent Shield (Scarab Brooch)
5971 basepoints0
= int32(damage
* 0.15f
);
5976 case SPELLFAMILY_WARRIOR
:
5979 if((auraSpellInfo
->SpellFamilyFlags
& 0x100000) && auraSpellInfo
->SpellIconID
==2006)
5981 //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed)
5982 //and effect[1]==TriggerSpell
5983 if(auraSpellInfo
->Effect
[1]!=SPELL_EFFECT_TRIGGER_SPELL
)
5985 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura
->GetSpellProto()->Id
);
5988 triggered_spell_id
= auraSpellInfo
->EffectTriggerSpell
[1];
5989 break; // fall through to normal cast
5993 case SPELLFAMILY_WARLOCK
:
5996 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000 && auraSpellInfo
->SpellIconID
==1137)
5998 // last case for Hellfire that damage caster also but don't must stun caster
5999 if( pVictim
== this )
6004 switch (triggeredByAura
->GetId())
6006 case 18096: chance
= 13.0f
; break;
6007 case 18073: chance
= 26.0f
; break;
6009 if (!roll_chance_f(chance
))
6012 // Pyroclasm (instead non-existed triggered spell)
6013 triggered_spell_id
= 18093;
6018 if(auraSpellInfo
->SpellFamilyFlags
& 0x0000000000004000)
6021 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
6022 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
6024 //Improved Drain Soul
6025 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
6027 int32 value2
= CalculateSpellDamage((*i
)->GetSpellProto(),2,(*i
)->GetSpellProto()->EffectBasePoints
[2],this);
6028 basepoints0
= value2
* GetMaxPower(POWER_MANA
) / 100;
6030 CastCustomSpell(this, 18371, &basepoints0
, NULL
, NULL
, true, castItem
, triggeredByAura
);
6034 // Not remove charge (aura removed on death in any cases)
6035 // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
6040 case SPELLFAMILY_PRIEST
:
6043 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
&& auraSpellInfo
->SpellIconID
==1875)
6045 switch (triggeredByAura
->GetSpellProto()->Id
)
6047 case 27811: triggered_spell_id
= 27813; break;
6048 case 27815: triggered_spell_id
= 27817; break;
6049 case 27816: triggered_spell_id
= 27818; break;
6051 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
6055 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
6056 basepoints0
= heal_amount
/3;
6061 if((auraSpellInfo
->SpellFamilyFlags
& 0x80000000LL
) && auraSpellInfo
->SpellVisual
[0]==7958)
6063 switch(triggeredByAura
->GetSpellProto()->Id
)
6066 triggered_spell_id
= 28377; break; // Rank 1
6068 triggered_spell_id
= 28378; break; // Rank 2
6070 triggered_spell_id
= 28379; break; // Rank 3
6072 triggered_spell_id
= 28380; break; // Rank 4
6074 triggered_spell_id
= 28381; break; // Rank 5
6076 triggered_spell_id
= 28382; break; // Rank 6
6078 triggered_spell_id
= 28385; break; // Rank 7
6080 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
6088 case SPELLFAMILY_DRUID
:
6090 switch(auraSpellInfo
->Id
)
6092 // Leader of the Pack (triggering Improved Leader of the Pack heal)
6095 if (triggeredByAura
->GetModifier()->m_amount
== 0)
6097 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6098 triggered_spell_id
= 34299;
6101 // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form)
6108 triggered_spell_id
=37340; break;// Ursine Blessing
6110 triggered_spell_id
=37341; break;// Feline Blessing
6112 triggered_spell_id
=37342; break;// Slyvan Blessing
6114 triggered_spell_id
=37343; break;// Lunar Blessing
6116 triggered_spell_id
=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN)
6127 case SPELLFAMILY_ROGUE
:
6129 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000LL
)
6131 switch(auraSpellInfo
->SpellIconID
)
6136 // skip non offhand attacks
6137 if(attackType
!=OFF_ATTACK
)
6139 break; // fall through to normal cast
6145 case SPELLFAMILY_PALADIN
:
6147 if(auraSpellInfo
->SpellFamilyFlags
== 0x00000000LL
)
6149 switch(auraSpellInfo
->Id
)
6151 // Lightning Capacitor
6154 // trinket ProcTriggerSpell but for safe checks for player
6155 if(!castItem
|| !pVictim
|| !pVictim
->isAlive() || GetTypeId()!=TYPEID_PLAYER
)
6158 if(((Player
*)this)->HasSpellCooldown(37657))
6162 CastSpell(this, 37658, true, castItem
, triggeredByAura
);
6163 // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown
6164 ((Player
*)this)->AddSpellCooldown(37657,0,time(NULL
)+(roll_chance_i(50) ? 2 : 3));
6168 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
6169 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
6170 if((*itr
)->GetId()==37658)
6173 // release at 3 aura in stack
6175 return true; // main triggered spell casted anyway
6177 RemoveAurasDueToSpell(37658);
6178 CastSpell(pVictim
, 37661, true, castItem
, triggeredByAura
);
6183 // Healing Trance (instead non-existed triggered spell)
6184 triggered_spell_id
= 37706;
6187 // HoTs on Heals (Fel Reaver's Piston trinket)
6190 // at direct heal effect
6191 if(!procSpell
|| !IsSpellHaveEffect(procSpell
,SPELL_EFFECT_HEAL
))
6194 // single proc at time
6195 AuraList
const& scAuras
= GetSingleCastAuras();
6196 for(AuraList::const_iterator itr
= scAuras
.begin(); itr
!= scAuras
.end(); ++itr
)
6197 if((*itr
)->GetId()==triggered_spell_id
)
6200 // positive cast at victim instead self
6205 switch(auraSpellInfo
->SpellIconID
)
6209 switch(auraSpellInfo
->EffectTriggerSpell
[0])
6217 // procspell is triggered spell but we need mana cost of original casted spell
6218 uint32 originalSpellId
= procSpell
->Id
;
6221 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
)
6223 if(procSpell
->SpellFamilyFlags
& 0x0001000000000000LL
)
6225 switch(procSpell
->Id
)
6227 case 25914: originalSpellId
= 20473; break;
6228 case 25913: originalSpellId
= 20929; break;
6229 case 25903: originalSpellId
= 20930; break;
6230 case 27175: originalSpellId
= 27174; break;
6231 case 33074: originalSpellId
= 33072; break;
6233 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
6239 SpellEntry
const *originalSpell
= sSpellStore
.LookupEntry(originalSpellId
);
6242 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId
);
6246 // percent stored in effect 1 (class scripts) base points
6247 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
6249 basepoints0
= originalSpell
->manaCost
*percent
/100;
6250 triggered_spell_id
= 20272;
6259 if(auraSpellInfo
->SpellFamilyFlags
& 0x00080000)
6261 switch(auraSpellInfo
->SpellIconID
)
6263 //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc
6266 if(!pVictim
|| !pVictim
->isAlive())
6269 switch(triggeredByAura
->GetSpellProto()->Id
)
6272 triggered_spell_id
= 20268; // Rank 1
6275 triggered_spell_id
= 20352; // Rank 2
6278 triggered_spell_id
= 20353; // Rank 3
6281 triggered_spell_id
= 27165; // Rank 4
6284 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoW",triggeredByAura
->GetSpellProto()->Id
);
6288 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6289 return true; // no hidden cooldown
6291 //Judgement of Light
6294 if(!pVictim
|| !pVictim
->isAlive())
6297 // overwrite non existing triggered spell call in spell.dbc
6298 switch(triggeredByAura
->GetSpellProto()->Id
)
6301 triggered_spell_id
= 20267; // Rank 1
6304 triggered_spell_id
= 20341; // Rank 2
6307 triggered_spell_id
= 20342; // Rank 3
6310 triggered_spell_id
= 20343; // Rank 4
6313 triggered_spell_id
= 27163; // Rank 5
6316 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura
->GetSpellProto()->Id
);
6319 pVictim
->CastSpell(pVictim
,triggered_spell_id
,true,castItem
,triggeredByAura
,GetGUID());
6320 return true; // no hidden cooldown
6324 // custom check for proc spell
6325 switch(auraSpellInfo
->Id
)
6327 // Bonus Healing (item spell)
6330 if(!pVictim
|| !pVictim
->isAlive())
6333 // bonus if health < 50%
6334 if(pVictim
->GetHealth() >= pVictim
->GetMaxHealth()*triggeredByAura
->GetModifier()->m_amount
/100)
6337 // cast at target positive spell
6342 switch(triggered_spell_id
)
6346 // prevent chain of triggered spell from same triggered spell
6347 if(procSpell
&& procSpell
->Id
==20424)
6353 case SPELLFAMILY_SHAMAN
:
6355 if(auraSpellInfo
->SpellFamilyFlags
== 0x0000000000000000)
6357 switch(auraSpellInfo
->SpellIconID
)
6361 switch(auraSpellInfo
->Id
)
6363 case 23551: // Lightning Shield - Tier2: 8 pieces proc shield
6365 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6366 triggered_spell_id
= 23552;
6370 case 23552: // Lightning Shield - trigger shield damage
6372 // Lightning Shield (overwrite non existing triggered spell call in spell.dbc)
6373 triggered_spell_id
= 27635;
6380 // Mana Surge (Shaman T1 bonus)
6386 basepoints0
= procSpell
->manaCost
* 35/100;
6387 triggered_spell_id
= 23571;
6394 if(GetTypeId()!=TYPEID_PLAYER
)
6397 // damage taken that reduces below 30% health
6398 // does NOT mean you must have been >= 30% before
6399 if (10*(int32(GetHealth())-int32(damage
)) >= 3*GetMaxHealth())
6402 triggered_spell_id
= 31616;
6404 // need check cooldown now
6405 if( cooldown
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6408 basepoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100;
6410 if(pVictim
&& pVictim
->isAlive())
6411 pVictim
->getThreatManager().modifyThreatPercent(this,-10);
6417 // Water Shield (we can't set cooldown for main spell - it's player casted spell
6418 if((auraSpellInfo
->SpellFamilyFlags
& 0x0000002000000000LL
) && auraSpellInfo
->SpellVisual
[0]==7358)
6425 if((auraSpellInfo
->SpellFamilyFlags
& 0x00000400) && auraSpellInfo
->SpellVisual
[0]==37)
6427 // overwrite non existing triggered spell call in spell.dbc
6428 switch(triggeredByAura
->GetSpellProto()->Id
)
6431 triggered_spell_id
= 26364; break; // Rank 1
6433 triggered_spell_id
= 26365; break; // Rank 2
6435 triggered_spell_id
= 26366; break; // Rank 3
6437 triggered_spell_id
= 26367; break; // Rank 4
6439 triggered_spell_id
= 26369; break; // Rank 5
6441 triggered_spell_id
= 26370; break; // Rank 6
6443 triggered_spell_id
= 26363; break; // Rank 7
6445 triggered_spell_id
= 26371; break; // Rank 8
6447 triggered_spell_id
= 26372; break; // Rank 9
6449 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
6460 // standard non-dummy case
6461 if(!triggered_spell_id
)
6463 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
6467 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6471 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex(),triggered_spell_id
);
6475 // not allow proc extra attack spell at extra attack
6476 if( m_extraAttacks
&& IsSpellHaveEffect(triggerEntry
,SPELL_EFFECT_ADD_EXTRA_ATTACKS
) )
6479 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6483 if(!target
|| target
!=this && !target
->isAlive())
6487 CastCustomSpell(target
,triggered_spell_id
,&basepoints0
,NULL
,NULL
,true,castItem
,triggeredByAura
);
6489 CastSpell(target
,triggered_spell_id
,true,castItem
,triggeredByAura
);
6491 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6492 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6497 bool Unit::HandleOverrideClassScriptAuraProc(Unit
*pVictim
, Aura
*triggeredByAura
, SpellEntry
const *procSpell
, uint32 cooldown
)
6499 int32 scriptId
= triggeredByAura
->GetModifier()->m_miscvalue
;
6501 if(!pVictim
|| !pVictim
->isAlive())
6504 Item
* castItem
= triggeredByAura
->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
6505 ? ((Player
*)this)->GetItemByGuid(triggeredByAura
->GetCastItemGUID()) : NULL
;
6507 uint32 triggered_spell_id
= 0;
6511 case 836: // Improved Blizzard (Rank 1)
6513 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6515 triggered_spell_id
= 12484;
6518 case 988: // Improved Blizzard (Rank 2)
6520 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6522 triggered_spell_id
= 12485;
6525 case 989: // Improved Blizzard (Rank 3)
6527 if (!procSpell
|| procSpell
->SpellVisual
[0]!=9487)
6529 triggered_spell_id
= 12486;
6532 case 4086: // Improved Mend Pet (Rank 1)
6533 case 4087: // Improved Mend Pet (Rank 2)
6535 int32 chance
= triggeredByAura
->GetSpellProto()->EffectBasePoints
[triggeredByAura
->GetEffIndex()];
6536 if(!roll_chance_i(chance
))
6539 triggered_spell_id
= 24406;
6542 case 4533: // Dreamwalker Raiment 2 pieces bonus
6545 if (!roll_chance_i(50))
6548 switch (pVictim
->getPowerType())
6550 case POWER_MANA
: triggered_spell_id
= 28722; break;
6551 case POWER_RAGE
: triggered_spell_id
= 28723; break;
6552 case POWER_ENERGY
: triggered_spell_id
= 28724; break;
6558 case 4537: // Dreamwalker Raiment 6 pieces bonus
6559 triggered_spell_id
= 28750; // Blessing of the Claw
6561 case 5497: // Improved Mana Gems (Serpent-Coil Braid)
6562 triggered_spell_id
= 37445; // Mana Surge
6567 if(!triggered_spell_id
)
6570 // standard non-dummy case
6571 SpellEntry
const* triggerEntry
= sSpellStore
.LookupEntry(triggered_spell_id
);
6575 sLog
.outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u",triggered_spell_id
,scriptId
);
6579 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->HasSpellCooldown(triggered_spell_id
))
6582 CastSpell(pVictim
, triggered_spell_id
, true, castItem
, triggeredByAura
);
6584 if( cooldown
&& GetTypeId()==TYPEID_PLAYER
)
6585 ((Player
*)this)->AddSpellCooldown(triggered_spell_id
,0,time(NULL
) + cooldown
);
6590 void Unit::setPowerType(Powers new_powertype
)
6592 SetByteValue(UNIT_FIELD_BYTES_0
, 3, new_powertype
);
6594 if(GetTypeId() == TYPEID_PLAYER
)
6596 if(((Player
*)this)->GetGroup())
6597 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
6599 else if(((Creature
*)this)->isPet())
6601 Pet
*pet
= ((Pet
*)this);
6602 if(pet
->isControlled())
6604 Unit
*owner
= GetOwner();
6605 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
6606 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE
);
6610 switch(new_powertype
)
6616 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
6617 SetPower( POWER_RAGE
,0);
6620 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6621 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
6624 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
6625 SetPower( POWER_ENERGY
,0);
6627 case POWER_HAPPINESS
:
6628 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6629 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
6634 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
6636 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
6639 static uint64 guid
= 0; // prevent repeating spam same faction problem
6641 if(GetGUID() != guid
)
6643 if(GetTypeId() == TYPEID_PLAYER
)
6644 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
6646 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
6653 bool Unit::IsHostileTo(Unit
const* unit
) const
6655 // always non-hostile to self
6659 // always non-hostile to GM in GM mode
6660 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6663 // always hostile to enemy
6664 if(getVictim()==unit
|| unit
->getVictim()==this)
6667 // test pet/charm masters instead pers/charmeds
6668 Unit
const* testerOwner
= GetCharmerOrOwner();
6669 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6671 // always hostile to owner's enemy
6672 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6675 // always hostile to enemy owner
6676 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6679 // always hostile to owner of owner's enemy
6680 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6683 Unit
const* tester
= testerOwner
? testerOwner
: this;
6684 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6686 // always non-hostile to target with common owner, or to owner/pet
6690 // special cases (Duel, etc)
6691 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6693 Player
const* pTester
= (Player
const*)tester
;
6694 Player
const* pTarget
= (Player
const*)target
;
6697 if(pTester
->duel
&& pTester
->duel
->opponent
== pTarget
&& pTester
->duel
->startTime
!= 0)
6701 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6705 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6709 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6713 // Green/Blue (can't attack)
6714 if(pTester
->GetTeam()==pTarget
->GetTeam())
6717 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
6718 return pTester
->IsPvP() && pTarget
->IsPvP();
6721 // faction base cases
6722 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6723 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6724 if(!tester_faction
|| !target_faction
)
6727 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6730 // PvC forced reaction and reputation case
6731 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6734 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6735 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
6736 return forceItr
->second
<= REP_HOSTILE
;
6738 // if faction have reputation then hostile state for tester at 100% dependent from at_war state
6739 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6740 if(raw_target_faction
->reputationListID
>=0)
6741 if(FactionState
const* factionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6742 return (factionState
->Flags
& FACTION_FLAG_AT_WAR
);
6744 // CvP forced reaction and reputation case
6745 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6748 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6749 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6750 return forceItr
->second
<= REP_HOSTILE
;
6752 // apply reputation state
6753 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
6754 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
6755 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
6758 // common faction based case (CvC,PvC,CvP)
6759 return tester_faction
->IsHostileTo(*target_faction
);
6762 bool Unit::IsFriendlyTo(Unit
const* unit
) const
6764 // always friendly to self
6768 // always friendly to GM in GM mode
6769 if(unit
->GetTypeId()==TYPEID_PLAYER
&& ((Player
const*)unit
)->isGameMaster())
6772 // always non-friendly to enemy
6773 if(getVictim()==unit
|| unit
->getVictim()==this)
6776 // test pet/charm masters instead pers/charmeds
6777 Unit
const* testerOwner
= GetCharmerOrOwner();
6778 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
6780 // always non-friendly to owner's enemy
6781 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
6784 // always non-friendly to enemy owner
6785 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
6788 // always non-friendly to owner of owner's enemy
6789 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
6792 Unit
const* tester
= testerOwner
? testerOwner
: this;
6793 Unit
const* target
= targetOwner
? targetOwner
: unit
;
6795 // always friendly to target with common owner, or to owner/pet
6799 // special cases (Duel)
6800 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
6802 Player
const* pTester
= (Player
const*)tester
;
6803 Player
const* pTarget
= (Player
const*)target
;
6806 if(pTester
->duel
&& pTester
->duel
->opponent
== target
&& pTester
->duel
->startTime
!= 0)
6810 if(pTester
->GetGroup() && pTester
->GetGroup()==pTarget
->GetGroup())
6814 if(pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
) && pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_SANCTUARY
))
6818 if(pTester
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
) && pTarget
->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_FFA_PVP
))
6822 // Green/Blue (non-attackable)
6823 if(pTester
->GetTeam()==pTarget
->GetTeam())
6826 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
6827 return !pTarget
->IsPvP();
6830 // faction base cases
6831 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
6832 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
6833 if(!tester_faction
|| !target_faction
)
6836 if(target
->isAttackingPlayer() && tester
->IsContestedGuard())
6839 // PvC forced reaction and reputation case
6840 if(tester
->GetTypeId()==TYPEID_PLAYER
)
6843 ForcedReactions::const_iterator forceItr
= ((Player
const*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
6844 if(forceItr
!=((Player
const*)tester
)->m_forcedReactions
.end())
6845 return forceItr
->second
>= REP_FRIENDLY
;
6847 // if faction have reputation then friendly state for tester at 100% dependent from at_war state
6848 if(FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
))
6849 if(raw_target_faction
->reputationListID
>=0)
6850 if(FactionState
const* FactionState
= ((Player
*)tester
)->GetFactionState(raw_target_faction
))
6851 return !(FactionState
->Flags
& FACTION_FLAG_AT_WAR
);
6853 // CvP forced reaction and reputation case
6854 else if(target
->GetTypeId()==TYPEID_PLAYER
)
6857 ForcedReactions::const_iterator forceItr
= ((Player
const*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
6858 if(forceItr
!=((Player
const*)target
)->m_forcedReactions
.end())
6859 return forceItr
->second
>= REP_FRIENDLY
;
6861 // apply reputation state
6862 if(FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
))
6863 if(raw_tester_faction
->reputationListID
>=0 )
6864 return ((Player
const*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
6867 // common faction based case (CvC,PvC,CvP)
6868 return tester_faction
->IsFriendlyTo(*target_faction
);
6871 bool Unit::IsHostileToPlayers() const
6873 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6877 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6878 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6881 return my_faction
->IsHostileToPlayers();
6884 bool Unit::IsNeutralToAll() const
6886 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
6890 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
6891 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
6894 return my_faction
->IsNeutralToAll();
6897 bool Unit::Attack(Unit
*victim
, bool meleeAttack
)
6899 if(!victim
|| victim
== this)
6902 // dead units can neither attack nor be attacked
6903 if(!isAlive() || !victim
->isAlive())
6906 // player cannot attack in mount state
6907 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
6910 // nobody can attack GM in GM-mode
6911 if(victim
->GetTypeId()==TYPEID_PLAYER
)
6913 if(((Player
*)victim
)->isGameMaster())
6918 if(((Creature
*)victim
)->IsInEvadeMode())
6922 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
6923 if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE
))
6924 RemoveSpellsCausingAura(SPELL_AURA_MOD_UNATTACKABLE
);
6928 if (m_attacking
== victim
)
6930 // switch to melee attack from ranged/magic
6931 if( meleeAttack
&& !hasUnitState(UNIT_STAT_MELEE_ATTACKING
) )
6933 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6934 SendAttackStart(victim
);
6943 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
6946 addUnitState(UNIT_STAT_MELEE_ATTACKING
);
6947 m_attacking
= victim
;
6948 m_attacking
->_addAttacker(this);
6950 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
6951 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
6953 if(GetTypeId()==TYPEID_UNIT
)
6955 WorldPacket
data(SMSG_AI_REACTION
, 12);
6956 data
<< uint64(GetGUID());
6957 data
<< uint32(AI_REACTION_AGGRO
); // Aggro sound
6958 ((WorldObject
*)this)->SendMessageToSet(&data
, true);
6960 ((Creature
*)this)->CallAssistance();
6961 ((Creature
*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
6964 // delay offhand weapon attack to next attack time
6965 if(haveOffhandWeapon())
6966 resetAttackTimer(OFF_ATTACK
);
6969 SendAttackStart(victim
);
6974 bool Unit::AttackStop()
6979 Unit
* victim
= m_attacking
;
6981 m_attacking
->_removeAttacker(this);
6985 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
6987 clearUnitState(UNIT_STAT_MELEE_ATTACKING
);
6989 InterruptSpell(CURRENT_MELEE_SPELL
);
6991 if( GetTypeId()==TYPEID_UNIT
)
6993 // reset call assistance
6994 ((Creature
*)this)->SetNoCallAssistance(false);
6997 SendAttackStop(victim
);
7002 void Unit::CombatStop(bool cast
)
7004 if(cast
& IsNonMeleeSpellCasted(false))
7005 InterruptNonMeleeSpells(false);
7008 RemoveAllAttackers();
7009 if( GetTypeId()==TYPEID_PLAYER
)
7010 ((Player
*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
7014 void Unit::CombatStopWithPets(bool cast
)
7017 if(Pet
* pet
= GetPet())
7018 pet
->CombatStop(cast
);
7019 if(Unit
* charm
= GetCharm())
7020 charm
->CombatStop(cast
);
7021 if(GetTypeId()==TYPEID_PLAYER
)
7023 GuardianPetList
const& guardians
= ((Player
*)this)->GetGuardians();
7024 for(GuardianPetList::const_iterator itr
= guardians
.begin(); itr
!= guardians
.end(); ++itr
)
7025 if(Unit
* guardian
= Unit::GetUnit(*this,*itr
))
7026 guardian
->CombatStop(cast
);
7030 bool Unit::isAttackingPlayer() const
7032 if(hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
7035 Pet
* pet
= GetPet();
7036 if(pet
&& pet
->isAttackingPlayer())
7039 Unit
* charmed
= GetCharm();
7040 if(charmed
&& charmed
->isAttackingPlayer())
7043 for (int8 i
= 0; i
< MAX_TOTEM
; i
++)
7047 Creature
*totem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7048 if(totem
&& totem
->isAttackingPlayer())
7056 void Unit::RemoveAllAttackers()
7058 while (!m_attackers
.empty())
7060 AttackerSet::iterator iter
= m_attackers
.begin();
7061 if(!(*iter
)->AttackStop())
7063 sLog
.outError("WORLD: Unit has an attacker that isn't attacking it!");
7064 m_attackers
.erase(iter
);
7069 void Unit::ModifyAuraState(AuraState flag
, bool apply
)
7073 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
7075 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7076 if(GetTypeId() == TYPEID_PLAYER
)
7078 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
7079 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
7081 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
7082 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
7083 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
7084 if (spellInfo
->CasterAuraState
== flag
)
7085 CastSpell(this, itr
->first
, true, NULL
);
7092 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
7094 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
7095 Unit::AuraMap
& tAuras
= GetAuras();
7096 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
7098 SpellEntry
const* spellProto
= (*itr
).second
->GetSpellProto();
7099 if (spellProto
->CasterAuraState
== flag
)
7101 // exceptions (applied at state but not removed at state change)
7103 if(spellProto
->SpellIconID
==2006 && spellProto
->SpellFamilyName
==SPELLFAMILY_WARRIOR
&& spellProto
->SpellFamilyFlags
==0x100000)
7118 Unit
*Unit::GetOwner() const
7120 uint64 ownerid
= GetOwnerGUID();
7123 return ObjectAccessor::GetUnit(*this, ownerid
);
7126 Unit
*Unit::GetCharmer() const
7128 if(uint64 charmerid
= GetCharmerGUID())
7129 return ObjectAccessor::GetUnit(*this, charmerid
);
7133 Player
* Unit::GetCharmerOrOwnerPlayerOrPlayerItself()
7135 uint64 guid
= GetCharmerOrOwnerGUID();
7136 if(IS_PLAYER_GUID(guid
))
7137 return ObjectAccessor::GetPlayer(*this, guid
);
7139 return GetTypeId()==TYPEID_PLAYER
? (Player
*)this : NULL
;
7142 Pet
* Unit::GetPet() const
7144 if(uint64 pet_guid
= GetPetGUID())
7146 if(Pet
* pet
= ObjectAccessor::GetPet(pet_guid
))
7149 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
7150 const_cast<Unit
*>(this)->SetPet(0);
7156 Unit
* Unit::GetCharm() const
7158 if(uint64 charm_guid
= GetCharmGUID())
7160 if(Unit
* pet
= ObjectAccessor::GetUnit(*this, charm_guid
))
7163 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
7164 const_cast<Unit
*>(this)->SetCharm(0);
7170 void Unit::SetPet(Pet
* pet
)
7172 SetUInt64Value(UNIT_FIELD_SUMMON
, pet
? pet
->GetGUID() : 0);
7174 // FIXME: hack, speed must be set only at follow
7176 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
7177 pet
->SetSpeed(UnitMoveType(i
), m_speed_rate
[i
], true);
7180 void Unit::SetCharm(Unit
* pet
)
7182 SetUInt64Value(UNIT_FIELD_CHARM
, pet
? pet
->GetGUID() : 0);
7184 if(GetTypeId() == TYPEID_PLAYER
)
7185 ((Player
*)this)->m_mover
= pet
? pet
: this;
7188 void Unit::UnsummonAllTotems()
7190 for (int8 i
= 0; i
< MAX_TOTEM
; ++i
)
7195 Creature
*OldTotem
= ObjectAccessor::GetCreature(*this, m_TotemSlot
[i
]);
7196 if (OldTotem
&& OldTotem
->isTotem())
7197 ((Totem
*)OldTotem
)->UnSummon();
7201 void Unit::SendHealSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
7204 WorldPacket
data(SMSG_SPELLHEALLOG
, (8+8+4+4+1));
7205 data
.append(pVictim
->GetPackGUID());
7206 data
.append(GetPackGUID());
7207 data
<< uint32(SpellID
);
7208 data
<< uint32(Damage
);
7209 data
<< uint32(0); // over healing?
7210 data
<< uint8(critical
? 1 : 0);
7211 data
<< uint8(0); // unused in client?
7212 SendMessageToSet(&data
, true);
7215 void Unit::SendEnergizeSpellLog(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, Powers powertype
)
7217 WorldPacket
data(SMSG_SPELLENERGIZELOG
, (8+8+4+4+4+1));
7218 data
.append(pVictim
->GetPackGUID());
7219 data
.append(GetPackGUID());
7220 data
<< uint32(SpellID
);
7221 data
<< uint32(powertype
);
7222 data
<< uint32(Damage
);
7223 SendMessageToSet(&data
, true);
7226 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
7228 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
7231 int32 BonusDamage
= 0;
7232 if( GetTypeId()==TYPEID_UNIT
)
7234 // Pets just add their bonus damage to their spell damage
7235 // note that their spell damage is just gain of their own auras
7236 if (((Creature
*)this)->isPet())
7238 BonusDamage
= ((Pet
*)this)->GetBonusDamage();
7240 // For totems get damage bonus from owner (statue isn't totem in fact)
7241 else if (((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7243 if(Unit
* owner
= GetOwner())
7244 return owner
->SpellDamageBonus(pVictim
, spellProto
, pdamage
, damagetype
);
7249 uint32 CastingTime
= !IsChanneledSpell(spellProto
) ? GetSpellCastTime(spellProto
) : GetSpellDuration(spellProto
);
7251 // Taken/Done fixed damage bonus auras
7252 int32 DoneAdvertisedBenefit
= SpellBaseDamageBonus(GetSpellSchoolMask(spellProto
))+BonusDamage
;
7253 int32 TakenAdvertisedBenefit
= SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7255 // Damage over Time spells bonus calculation
7256 float DotFactor
= 1.0f
;
7257 if(damagetype
== DOT
)
7259 int32 DotDuration
= GetSpellDuration(spellProto
);
7263 if(DotDuration
> 30000) DotDuration
= 30000;
7264 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7266 for(int j
= 0; j
< 3; j
++)
7268 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7269 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_DAMAGE
||
7270 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7277 if(spellProto
->EffectAmplitude
[x
] != 0)
7278 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7281 DoneAdvertisedBenefit
/= DotTicks
;
7282 TakenAdvertisedBenefit
/= DotTicks
;
7287 // Taken/Done total percent damage auras
7288 float DoneTotalMod
= 1.0f
;
7289 float TakenTotalMod
= 1.0f
;
7292 AuraList
const& mModDamagePercentDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
7293 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
7295 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) &&
7296 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7297 // -1 == any item class (not wand then)
7298 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7299 // 0 == any inventory type (not wand then)
7301 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7305 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7306 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
7307 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
7308 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7309 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7312 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
7313 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
7314 if( (*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
) )
7315 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
7317 // .. taken pct: scripted (increases damage of * against targets *)
7318 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7319 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7321 switch((*i
)->GetModifier()->m_miscvalue
)
7324 case 4920: case 4919:
7325 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
))
7326 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
; break;
7330 // .. taken pct: dummy auras
7331 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7332 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
7334 switch((*i
)->GetSpellProto()->SpellIconID
)
7338 if( ((*i
)->GetModifier()->m_miscvalue
& GetSpellSchoolMask(spellProto
)) )
7340 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
7342 float mod
= -((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
)*2*4;
7343 if (mod
< (*i
)->GetModifier()->m_amount
)
7344 mod
= (*i
)->GetModifier()->m_amount
;
7345 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
7350 for(int j
=0;j
<3;j
++)
7352 if(GetEffectMechanic(spellProto
, j
)==MECHANIC_BLEED
)
7354 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
7362 // Distribute Damage over multiple effects, reduce by AoE
7363 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7365 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
7366 for(int j
= 0; j
< 3; ++j
)
7368 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7369 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7376 switch(spellProto
->SpellFamilyName
)
7378 case SPELLFAMILY_MAGE
:
7379 // Ignite - do not modify, it is (8*Rank)% damage of procing Spell
7380 if(spellProto
->Id
==12654)
7385 else if((spellProto
->SpellFamilyFlags
& 0x20000LL
) && spellProto
->SpellIconID
== 186)
7387 CastingTime
/= 3; // applied 1/3 bonuses in case generic target
7388 if(pVictim
->isFrozen()) // and compensate this for frozen target.
7389 TakenTotalMod
*= 3.0f
;
7391 // Pyroblast - 115% of Fire Damage, DoT - 20% of Fire Damage
7392 else if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 184 )
7394 DotFactor
= damagetype
== DOT
? 0.2f
: 1.0f
;
7395 CastingTime
= damagetype
== DOT
? 3500 : 4025;
7397 // Fireball - 100% of Fire Damage, DoT - 0% of Fire Damage
7398 else if((spellProto
->SpellFamilyFlags
& 0x1LL
) && spellProto
->SpellIconID
== 185)
7401 DotFactor
= damagetype
== DOT
? 0.0f
: 1.0f
;
7404 else if (spellProto
->SpellFamilyFlags
& 0x0000000800000000LL
)
7408 // Arcane Missiles triggered spell
7409 else if ((spellProto
->SpellFamilyFlags
& 0x200000LL
) && spellProto
->SpellIconID
== 225)
7413 // Blizzard triggered spell
7414 else if ((spellProto
->SpellFamilyFlags
& 0x80080LL
) && spellProto
->SpellIconID
== 285)
7419 case SPELLFAMILY_WARLOCK
:
7421 if((spellProto
->SpellFamilyFlags
& 0x40000LL
) && spellProto
->SpellIconID
== 208)
7423 CastingTime
= 2800; // 80% from +shadow damage
7424 DoneTotalMod
= 1.0f
;
7425 TakenTotalMod
= 1.0f
;
7428 else if((spellProto
->SpellFamilyFlags
& 0x80000000LL
) && spellProto
->SpellIconID
== 154 && GetPetGUID())
7430 CastingTime
= 3360; // 96% from +shadow damage
7431 DoneTotalMod
= 1.0f
;
7432 TakenTotalMod
= 1.0f
;
7434 // Soul Fire - 115% of Fire Damage
7435 else if((spellProto
->SpellFamilyFlags
& 0x8000000000LL
) && spellProto
->SpellIconID
== 184)
7439 // Curse of Agony - 120% of Shadow Damage
7440 else if((spellProto
->SpellFamilyFlags
& 0x0000000400LL
) && spellProto
->SpellIconID
== 544)
7444 // Drain Mana - 0% of Shadow Damage
7445 else if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 548)
7449 // Drain Soul 214.3%
7450 else if ((spellProto
->SpellFamilyFlags
& 0x4000LL
) && spellProto
->SpellIconID
== 113 )
7455 else if ((spellProto
->SpellFamilyFlags
& 0x40LL
) && spellProto
->SpellIconID
== 937)
7457 CastingTime
= damagetype
== DOT
? 5000 : 500; // self damage seems to be so
7459 // Unstable Affliction - 180%
7460 else if (spellProto
->Id
== 31117 && spellProto
->SpellIconID
== 232)
7465 else if ((spellProto
->SpellFamilyFlags
& 0x2LL
) && spellProto
->SpellIconID
== 313)
7470 case SPELLFAMILY_PALADIN
:
7471 // Consecration - 95% of Holy Damage
7472 if((spellProto
->SpellFamilyFlags
& 0x20LL
) && spellProto
->SpellIconID
== 51)
7477 // Seal of Righteousness - 10.2%/9.8% ( based on weapon type ) of Holy Damage, multiplied by weapon speed
7478 else if((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 25)
7480 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
7481 float wspeed
= GetAttackTime(BASE_ATTACK
)/1000.0f
;
7483 if( item
&& item
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
)
7484 CastingTime
= uint32(wspeed
*3500*0.102f
);
7486 CastingTime
= uint32(wspeed
*3500*0.098f
);
7488 // Judgement of Righteousness - 73%
7489 else if ((spellProto
->SpellFamilyFlags
& 1024) && spellProto
->SpellIconID
== 25)
7493 // Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
7494 else if ((spellProto
->SpellFamilyFlags
& 0x80000000000LL
) && spellProto
->SpellIconID
== 2292)
7499 // Holy shield - 5% of Holy Damage
7500 else if ((spellProto
->SpellFamilyFlags
& 0x4000000000LL
) && spellProto
->SpellIconID
== 453)
7504 // Blessing of Sanctuary - 0%
7505 else if ((spellProto
->SpellFamilyFlags
& 0x10000000LL
) && spellProto
->SpellIconID
== 29)
7509 // Seal of Righteousness trigger - already computed for parent spell
7510 else if ( spellProto
->SpellFamilyName
==SPELLFAMILY_PALADIN
&& spellProto
->SpellIconID
==25 && spellProto
->AttributesEx4
& 0x00800000LL
)
7515 case SPELLFAMILY_SHAMAN
:
7517 if (spellProto
->SpellFamilyFlags
& 0x000040000000LL
)
7519 if (spellProto
->SpellIconID
== 33) // Fire Nova totem attack must be 21.4%(untested)
7520 CastingTime
= 749; // ignore CastingTime and use as modifier
7521 else if (spellProto
->SpellIconID
== 680) // Searing Totem attack 8%
7522 CastingTime
= 280; // ignore CastingTime and use as modifier
7523 else if (spellProto
->SpellIconID
== 37) // Magma totem attack must be 6.67%(untested)
7524 CastingTime
= 234; // ignore CastingTimePenalty and use as modifier
7526 // Lightning Shield (and proc shield from T2 8 pieces bonus ) 33% per charge
7527 else if( (spellProto
->SpellFamilyFlags
& 0x00000000400LL
) || spellProto
->Id
== 23552)
7528 CastingTime
= 1155; // ignore CastingTimePenalty and use as modifier
7530 case SPELLFAMILY_PRIEST
:
7531 // Mana Burn - 0% of Shadow Damage
7532 if((spellProto
->SpellFamilyFlags
& 0x10LL
) && spellProto
->SpellIconID
== 212)
7536 // Mind Flay - 59% of Shadow Damage
7537 else if((spellProto
->SpellFamilyFlags
& 0x800000LL
) && spellProto
->SpellIconID
== 548)
7541 // Holy Fire - 86.71%, DoT - 16.5%
7542 else if ((spellProto
->SpellFamilyFlags
& 0x100000LL
) && spellProto
->SpellIconID
== 156)
7544 DotFactor
= damagetype
== DOT
? 0.165f
: 1.0f
;
7545 CastingTime
= damagetype
== DOT
? 3500 : 3035;
7547 // Shadowguard - 28% per charge
7548 else if ((spellProto
->SpellFamilyFlags
& 0x2000000LL
) && spellProto
->SpellIconID
== 19)
7552 // Touch of Weakeness - 10%
7553 else if ((spellProto
->SpellFamilyFlags
& 0x80000LL
) && spellProto
->SpellIconID
== 1591)
7557 // Reflective Shield (back damage) - 0% (other spells fit to check not have damage effects/auras)
7558 else if (spellProto
->SpellFamilyFlags
== 0 && spellProto
->SpellIconID
== 566)
7563 else if ((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 1874)
7568 case SPELLFAMILY_DRUID
:
7569 // Hurricane triggered spell
7570 if((spellProto
->SpellFamilyFlags
& 0x400000LL
) && spellProto
->SpellIconID
== 220)
7575 case SPELLFAMILY_WARRIOR
:
7576 case SPELLFAMILY_HUNTER
:
7577 case SPELLFAMILY_ROGUE
:
7584 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7586 // Spellmod SpellDamage
7587 float SpellModSpellDamage
= 100.0f
;
7589 if(Player
* modOwner
= GetSpellModOwner())
7590 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7592 SpellModSpellDamage
/= 100.0f
;
7594 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7595 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * DotFactor
* LvlPenalty
;
7597 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
7599 // Add flat bonus from spell damage versus
7600 tmpDamage
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
, creatureTypeMask
);
7602 // apply spellmod to Done damage
7603 if(Player
* modOwner
= GetSpellModOwner())
7604 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, tmpDamage
);
7606 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
7608 if( GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() )
7609 tmpDamage
*= ((Creature
*)this)->GetSpellDamageMod(((Creature
*)this)->GetCreatureInfo()->rank
);
7611 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
7614 int32
Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask
)
7616 int32 DoneAdvertisedBenefit
= 0;
7619 AuraList
const& mDamageDone
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
7620 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
7621 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0 &&
7622 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
7623 // -1 == any item class (not wand then)
7624 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
7625 // 0 == any inventory type (not wand then)
7626 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7628 if (GetTypeId() == TYPEID_PLAYER
)
7630 // Damage bonus from stats
7631 AuraList
const& mDamageDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
);
7632 for(AuraList::const_iterator i
= mDamageDoneOfStatPercent
.begin();i
!= mDamageDoneOfStatPercent
.end(); ++i
)
7634 if((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7636 SpellEntry
const* iSpellProto
= (*i
)->GetSpellProto();
7637 uint8 eff
= (*i
)->GetEffIndex();
7639 // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index)
7640 Stats usedStat
= STAT_INTELLECT
;
7641 if(eff
< 2 && iSpellProto
->EffectApplyAuraName
[eff
+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
)
7642 usedStat
= Stats(iSpellProto
->EffectMiscValue
[eff
+1]);
7644 DoneAdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7647 // ... and attack power
7648 AuraList
const& mDamageDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
);
7649 for(AuraList::const_iterator i
=mDamageDonebyAP
.begin();i
!= mDamageDonebyAP
.end(); ++i
)
7650 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7651 DoneAdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7654 return DoneAdvertisedBenefit
;
7657 int32
Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
7659 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7661 int32 TakenAdvertisedBenefit
= 0;
7662 // ..done (for creature type by mask) in taken
7663 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
7664 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
7665 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
7666 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7669 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
7670 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
7671 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7672 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7674 return TakenAdvertisedBenefit
;
7677 bool Unit::isSpellCrit(Unit
*pVictim
, SpellEntry
const *spellProto
, SpellSchoolMask schoolMask
, WeaponAttackType attackType
)
7679 // not critting spell
7680 if((spellProto
->AttributesEx2
& SPELL_ATTR_EX2_CANT_CRIT
))
7683 float crit_chance
= 0.0f
;
7684 switch(spellProto
->DmgClass
)
7686 case SPELL_DAMAGE_CLASS_NONE
:
7688 case SPELL_DAMAGE_CLASS_MAGIC
:
7690 if (schoolMask
& SPELL_SCHOOL_MASK_NORMAL
)
7692 // For other schools
7693 else if (GetTypeId() == TYPEID_PLAYER
)
7694 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ GetFirstSchoolInMask(schoolMask
));
7697 crit_chance
= m_baseSpellCritChance
;
7698 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7701 if (pVictim
&& !IsPositiveSpell(spellProto
->Id
))
7703 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7704 crit_chance
+= pVictim
->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
, schoolMask
);
7705 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7706 crit_chance
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
7707 // Modify by player victim resilience
7708 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
7709 crit_chance
-= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL
);
7710 // scripted (increase crit chance ... against ... target by x%
7711 if(pVictim
->isFrozen()) // Shatter
7713 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
7714 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
7716 switch((*i
)->GetModifier()->m_miscvalue
)
7718 case 849: crit_chance
+= 10.0f
; break; //Shatter Rank 1
7719 case 910: crit_chance
+= 20.0f
; break; //Shatter Rank 2
7720 case 911: crit_chance
+= 30.0f
; break; //Shatter Rank 3
7721 case 912: crit_chance
+= 40.0f
; break; //Shatter Rank 4
7722 case 913: crit_chance
+= 50.0f
; break; //Shatter Rank 5
7729 case SPELL_DAMAGE_CLASS_MELEE
:
7730 case SPELL_DAMAGE_CLASS_RANGED
:
7734 crit_chance
= GetUnitCriticalChance(attackType
, pVictim
);
7735 crit_chance
+= (int32(GetMaxSkillValueForLevel(pVictim
)) - int32(pVictim
->GetDefenseSkillValue(this))) * 0.04f
;
7736 crit_chance
+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
, schoolMask
);
7744 // only players use intelligence for critical chance computations
7745 if(Player
* modOwner
= GetSpellModOwner())
7746 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
7748 crit_chance
= crit_chance
> 0.0f
? crit_chance
: 0.0f
;
7749 if (roll_chance_f(crit_chance
))
7754 uint32
Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, uint32 damage
, Unit
*pVictim
)
7756 // Calculate critical bonus
7758 switch(spellProto
->DmgClass
)
7760 case SPELL_DAMAGE_CLASS_MELEE
: // for melee based spells is 100%
7761 case SPELL_DAMAGE_CLASS_RANGED
:
7762 // TODO: write here full calculation for melee/ranged spells
7763 crit_bonus
= damage
;
7766 crit_bonus
= damage
/ 2; // for spells is 50%
7770 // adds additional damage to crit_bonus (from talents)
7771 if(Player
* modOwner
= GetSpellModOwner())
7772 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
7776 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
7777 crit_bonus
= int32(crit_bonus
* GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
, creatureTypeMask
));
7781 damage
+= crit_bonus
;
7786 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
7788 // For totems get healing bonus from owner (statue isn't totem in fact)
7789 if( GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->isTotem() && ((Totem
*)this)->GetTotemType()!=TOTEM_STATUE
)
7790 if(Unit
* owner
= GetOwner())
7791 return owner
->SpellHealingBonus(spellProto
, healamount
, damagetype
, pVictim
);
7795 // These Spells are doing fixed amount of healing (TODO found less hack-like check)
7796 if (spellProto
->Id
== 15290 || spellProto
->Id
== 39373 ||
7797 spellProto
->Id
== 33778 || spellProto
->Id
== 379 ||
7798 spellProto
->Id
== 38395 || spellProto
->Id
== 40972)
7801 int32 AdvertisedBenefit
= SpellBaseHealingBonus(GetSpellSchoolMask(spellProto
));
7802 uint32 CastingTime
= GetSpellCastTime(spellProto
);
7805 AdvertisedBenefit
+= SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto
), pVictim
);
7807 // Blessing of Light dummy effects healing taken from Holy Light and Flash of Light
7808 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0x00000000C0000000LL
))
7810 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7811 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
7813 if((*i
)->GetSpellProto()->SpellVisual
[0] == 9180)
7816 if ((spellProto
->SpellFamilyFlags
& 0x0000000040000000LL
) && (*i
)->GetEffIndex() == 1)
7817 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7819 else if ((spellProto
->SpellFamilyFlags
& 0x0000000080000000LL
) && (*i
)->GetEffIndex() == 0)
7820 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7825 float ActualBenefit
= 0.0f
;
7827 if (AdvertisedBenefit
!= 0)
7829 // Healing over Time spells
7830 float DotFactor
= 1.0f
;
7831 if(damagetype
== DOT
)
7833 int32 DotDuration
= GetSpellDuration(spellProto
);
7837 if(DotDuration
> 30000) DotDuration
= 30000;
7838 if(!IsChanneledSpell(spellProto
)) DotFactor
= DotDuration
/ 15000.0f
;
7840 for(int j
= 0; j
< 3; j
++)
7842 if( spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& (
7843 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_HEAL
||
7844 spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
) )
7851 if(spellProto
->EffectAmplitude
[x
] != 0)
7852 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
7854 AdvertisedBenefit
/= DotTicks
;
7858 // distribute healing to all effects, reduce AoE damage
7859 CastingTime
= GetCastingTimeForBonus( spellProto
, damagetype
, CastingTime
);
7861 // 0% bonus for damage and healing spells for leech spells from healing bonus
7862 for(int j
= 0; j
< 3; ++j
)
7864 if( spellProto
->Effect
[j
] == SPELL_EFFECT_HEALTH_LEECH
||
7865 spellProto
->Effect
[j
] == SPELL_EFFECT_APPLY_AURA
&& spellProto
->EffectApplyAuraName
[j
] == SPELL_AURA_PERIODIC_LEECH
)
7873 switch (spellProto
->SpellFamilyName
)
7875 case SPELLFAMILY_SHAMAN
:
7876 // Healing stream from totem (add 6% per tick from hill bonus owner)
7877 if (spellProto
->SpellFamilyFlags
& 0x000000002000LL
)
7879 // Earth Shield 30% per charge
7880 else if (spellProto
->SpellFamilyFlags
& 0x40000000000LL
)
7883 case SPELLFAMILY_DRUID
:
7885 if (spellProto
->SpellFamilyFlags
& 0x1000000000LL
)
7887 CastingTime
= damagetype
== DOT
? 3500 : 1200;
7888 DotFactor
= damagetype
== DOT
? 0.519f
: 1.0f
;
7890 // Tranquility triggered spell
7891 else if (spellProto
->SpellFamilyFlags
& 0x80LL
)
7894 else if (spellProto
->SpellFamilyFlags
& 0x10LL
)
7897 else if (spellProto
->SpellFamilyFlags
& 0x40LL
)
7899 DotFactor
= damagetype
== DOT
? 0.705f
: 1.0f
;
7900 CastingTime
= damagetype
== DOT
? 3500 : 1010;
7903 case SPELLFAMILY_PRIEST
:
7905 if ((spellProto
->SpellFamilyFlags
& 0x8000000LL
) && spellProto
->SpellIconID
== 1874)
7908 case SPELLFAMILY_PALADIN
:
7909 // Seal and Judgement of Light
7910 if ( spellProto
->SpellFamilyFlags
& 0x100040000LL
)
7913 case SPELLFAMILY_WARRIOR
:
7914 case SPELLFAMILY_ROGUE
:
7915 case SPELLFAMILY_HUNTER
:
7920 float LvlPenalty
= CalculateLevelPenalty(spellProto
);
7922 // Spellmod SpellDamage
7923 float SpellModSpellDamage
= 100.0f
;
7925 if(Player
* modOwner
= GetSpellModOwner())
7926 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_BONUS_DAMAGE
,SpellModSpellDamage
);
7928 SpellModSpellDamage
/= 100.0f
;
7930 ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * DotFactor
* SpellModSpellDamage
* LvlPenalty
;
7933 // use float as more appropriate for negative values and percent applying
7934 float heal
= healamount
+ ActualBenefit
;
7936 // TODO: check for ALL/SPELLS type
7937 // Healing done percent
7938 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
7939 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
7940 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
7942 // apply spellmod to Done amount
7943 if(Player
* modOwner
= GetSpellModOwner())
7944 modOwner
->ApplySpellMod(spellProto
->Id
, damagetype
== DOT
? SPELLMOD_DOT
: SPELLMOD_DAMAGE
, heal
);
7946 // Healing Wave cast
7947 if (spellProto
->SpellFamilyName
== SPELLFAMILY_SHAMAN
&& spellProto
->SpellFamilyFlags
& 0x0000000000000040LL
)
7949 // Search for Healing Way on Victim (stack up to 3 time)
7951 Unit::AuraList
const& auraDummy
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
7952 for(Unit::AuraList::const_iterator itr
= auraDummy
.begin(); itr
!=auraDummy
.end(); ++itr
)
7953 if((*itr
)->GetId() == 29203)
7954 pctMod
+= (*itr
)->GetModifier()->m_amount
;
7957 heal
= heal
* (100 + pctMod
) / 100;
7960 // Healing taken percent
7961 float minval
= pVictim
->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7963 heal
*= (100.0f
+ minval
) / 100.0f
;
7965 float maxval
= pVictim
->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT
);
7967 heal
*= (100.0f
+ maxval
) / 100.0f
;
7969 if (heal
< 0) heal
= 0;
7971 return uint32(heal
);
7974 int32
Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask
)
7976 int32 AdvertisedBenefit
= 0;
7978 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
7979 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
7980 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
7981 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
7983 // Healing bonus of spirit, intellect and strength
7984 if (GetTypeId() == TYPEID_PLAYER
)
7986 // Healing bonus from stats
7987 AuraList
const& mHealingDoneOfStatPercent
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
);
7988 for(AuraList::const_iterator i
= mHealingDoneOfStatPercent
.begin();i
!= mHealingDoneOfStatPercent
.end(); ++i
)
7990 // stat used dependent from misc value (stat index)
7991 Stats usedStat
= Stats((*i
)->GetSpellProto()->EffectMiscValue
[(*i
)->GetEffIndex()]);
7992 AdvertisedBenefit
+= int32(GetStat(usedStat
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
7995 // ... and attack power
7996 AuraList
const& mHealingDonebyAP
= GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
);
7997 for(AuraList::const_iterator i
= mHealingDonebyAP
.begin();i
!= mHealingDonebyAP
.end(); ++i
)
7998 if ((*i
)->GetModifier()->m_miscvalue
& schoolMask
)
7999 AdvertisedBenefit
+= int32(GetTotalAttackPowerValue(BASE_ATTACK
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
8001 return AdvertisedBenefit
;
8004 int32
Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask
, Unit
*pVictim
)
8006 int32 AdvertisedBenefit
= 0;
8007 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING
);
8008 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8009 if(((*i
)->GetModifier()->m_miscvalue
& schoolMask
) != 0)
8010 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
8011 return AdvertisedBenefit
;
8014 bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask
, bool useCharges
)
8016 // no charges dependent checks
8017 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8018 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8019 if(itr
->type
& shoolMask
)
8022 // charges dependent checks
8023 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
8024 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
8026 if(itr
->type
& shoolMask
)
8030 AuraList
const& auraDamageImmunity
= GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY
);
8031 for(AuraList::const_iterator auraItr
= auraDamageImmunity
.begin(); auraItr
!= auraDamageImmunity
.end(); ++auraItr
)
8033 if((*auraItr
)->GetId()==itr
->spellId
)
8035 if((*auraItr
)->m_procCharges
> 0)
8037 --(*auraItr
)->m_procCharges
;
8038 if((*auraItr
)->m_procCharges
==0)
8039 RemoveAurasDueToSpell(itr
->spellId
);
8052 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
, bool useCharges
)
8059 //FIX ME this hack: don't get feared if stunned
8060 if (spellInfo
->Mechanic
== MECHANIC_FEAR
)
8062 if ( hasUnitState(UNIT_STAT_STUNNED
) )
8066 // not have spells with charges currently
8067 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
8068 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
8069 if(itr
->type
== spellInfo
->Dispel
)
8072 if( !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE
) && // unaffected by school immunity
8073 !(spellInfo
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)) // can remove immune (by dispell or immune it)
8075 // not have spells with charges currently
8076 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
8077 for(SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
8078 if( !(IsPositiveSpell(itr
->spellId
) && IsPositiveSpell(spellInfo
->Id
)) &&
8079 (itr
->type
& GetSpellSchoolMask(spellInfo
)) )
8083 // charges dependent checks
8085 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8086 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8088 if(itr
->type
== spellInfo
->Mechanic
)
8092 AuraList
const& auraMechImmunity
= GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY
);
8093 for(AuraList::const_iterator auraItr
= auraMechImmunity
.begin(); auraItr
!= auraMechImmunity
.end(); ++auraItr
)
8095 if((*auraItr
)->GetId()==itr
->spellId
)
8097 if((*auraItr
)->m_procCharges
> 0)
8099 --(*auraItr
)->m_procCharges
;
8100 if((*auraItr
)->m_procCharges
==0)
8101 RemoveAurasDueToSpell(itr
->spellId
);
8114 bool Unit::IsImmunedToSpellEffect(uint32 effect
, uint32 mechanic
) const
8116 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
8117 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
8118 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
8119 if(itr
->type
== effect
)
8122 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
8123 for (SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
8124 if(itr
->type
== mechanic
)
8130 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
8135 uint32 family
= spellInfo
->SpellFamilyName
;
8136 uint64 flags
= spellInfo
->SpellFamilyFlags
;
8138 if((family
== 5 && flags
== 256) || //Searing Pain
8139 (family
== 6 && flags
== 8192) || //Mind Blast
8140 (family
== 11 && flags
== 1048576)) //Earth Shock
8146 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
, SpellEntry
const *spellProto
)
8154 uint32 creatureTypeMask
= pVictim
->GetCreatureTypeMask();
8156 // Taken/Done fixed damage bonus auras
8157 int32 DoneFlatBenefit
= 0;
8158 int32 TakenFlatBenefit
= 0;
8160 // ..done (for creature type by mask) in taken
8161 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
8162 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
8163 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8164 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8167 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8169 // ..done (base at attack power for marked target and base at attack power for creature type)
8171 if(attType
== RANGED_ATTACK
)
8173 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
8175 // ..done (base at attack power and creature type)
8176 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
);
8177 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8178 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8179 APbonus
+= (*i
)->GetModifier()->m_amount
;
8183 APbonus
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
);
8185 // ..done (base at attack power and creature type)
8186 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
);
8187 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
8188 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8189 APbonus
+= (*i
)->GetModifier()->m_amount
;
8192 if (APbonus
!=0) // Can be negative
8194 bool normalized
= false;
8197 for (uint8 i
= 0; i
<3;i
++)
8199 if (spellProto
->Effect
[i
] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG
)
8207 DoneFlatBenefit
+= int32(APbonus
/14.0f
* GetAPMultiplier(attType
,normalized
));
8211 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
8212 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
8213 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8214 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
8216 if(attType
!=RANGED_ATTACK
)
8217 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
8219 TakenFlatBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
8221 // Done/Taken total percent damage auras
8222 float DoneTotalMod
= 1;
8223 float TakenTotalMod
= 1;
8226 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
8227 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
8229 AuraList
const& mDamageDoneVersus
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
);
8230 for(AuraList::const_iterator i
= mDamageDoneVersus
.begin();i
!= mDamageDoneVersus
.end(); ++i
)
8231 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
8232 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8235 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
8236 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
8237 if((*i
)->GetModifier()->m_miscvalue
& GetMeleeDamageSchoolMask())
8238 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8240 // .. taken pct: dummy auras
8241 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
8242 for(AuraList::const_iterator i
= mDummyAuras
.begin(); i
!= mDummyAuras
.end(); ++i
)
8244 switch((*i
)->GetSpellProto()->SpellIconID
)
8248 if((*i
)->GetModifier()->m_miscvalue
& SPELL_SCHOOL_MASK_NORMAL
)
8250 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
8252 float mod
= ((Player
*)pVictim
)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE
)*(-8.0f
);
8253 if (mod
< (*i
)->GetModifier()->m_amount
)
8254 mod
= (*i
)->GetModifier()->m_amount
;
8255 TakenTotalMod
*= (mod
+100.0f
)/100.0f
;
8260 if(spellProto
==NULL
)
8262 // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
8263 if(spellProto
->SpellFamilyName
==SPELLFAMILY_DRUID
&& (spellProto
->SpellFamilyFlags
==0x00008000LL
))
8264 TakenTotalMod
*= (100.0f
+(*i
)->GetModifier()->m_amount
)/100.0f
;
8269 // .. taken pct: class scripts
8270 AuraList
const& mclassScritAuras
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
8271 for(AuraList::const_iterator i
= mclassScritAuras
.begin(); i
!= mclassScritAuras
.end(); ++i
)
8273 switch((*i
)->GetMiscValue())
8275 case 6427: case 6428: // Dirty Deeds
8276 if(pVictim
->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
))
8278 Aura
* eff0
= GetAura((*i
)->GetId(),0);
8279 if(!eff0
|| (*i
)->GetEffIndex()!=1)
8281 sLog
.outError("Spell structure of DD (%u) changed.",(*i
)->GetId());
8285 // effect 0 have expected value but in negative state
8286 TakenTotalMod
*= (-eff0
->GetModifier()->m_amount
+100.0f
)/100.0f
;
8292 if(attType
!= RANGED_ATTACK
)
8294 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
8295 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
8296 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8300 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
8301 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
8302 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
8305 float tmpDamage
= float(int32(*pdamage
) + DoneFlatBenefit
) * DoneTotalMod
;
8307 // apply spellmod to Done damage
8310 if(Player
* modOwner
= GetSpellModOwner())
8311 modOwner
->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, tmpDamage
);
8314 tmpDamage
= (tmpDamage
+ TakenFlatBenefit
)*TakenTotalMod
;
8316 // bonus result can be negative
8317 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
8320 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
8324 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
8327 if(itr
->type
== type
)
8329 m_spellImmune
[op
].erase(itr
);
8330 next
= m_spellImmune
[op
].begin();
8334 Immune
.spellId
= spellId
;
8336 m_spellImmune
[op
].push_back(Immune
);
8340 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
8342 if(itr
->spellId
== spellId
)
8344 m_spellImmune
[op
].erase(itr
);
8352 void Unit::ApplySpellDispelImmunity(const SpellEntry
* spellProto
, DispelType type
, bool apply
)
8354 ApplySpellImmune(spellProto
->Id
,IMMUNITY_DISPEL
, type
, apply
);
8356 if (apply
&& spellProto
->AttributesEx
& SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
)
8357 RemoveAurasWithDispelType(type
);
8360 float Unit::GetWeaponProcChance() const
8362 // normalized proc chance for weapon attack speed
8364 if(isAttackReady(BASE_ATTACK
))
8365 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
8366 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
8367 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
8371 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
8373 // proc per minute chance calculation
8374 if (PPM
<= 0) return 0.0f
;
8375 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8379 void Unit::Mount(uint32 mount
)
8384 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNTING
);
8386 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
8388 SetFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8391 if(GetTypeId() == TYPEID_PLAYER
)
8393 Pet
* pet
= GetPet();
8396 if(pet
->isControlled())
8398 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(pet
->GetCharmInfo()->GetPetNumber());
8399 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
8402 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
8405 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8409 void Unit::Unmount()
8414 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED
);
8416 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
8417 RemoveFlag( UNIT_FIELD_FLAGS
, UNIT_FLAG_MOUNT
);
8419 // only resummon old pet if the player is already added to a map
8420 // this prevents adding a pet to a not created map which would otherwise cause a crash
8421 // (it could probably happen when logging in after a previous crash)
8422 if(GetTypeId() == TYPEID_PLAYER
&& IsInWorld() && ((Player
*)this)->GetTemporaryUnsummonedPetNumber() && isAlive())
8424 Pet
* NewPet
= new Pet
;
8425 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetTemporaryUnsummonedPetNumber(), true))
8428 ((Player
*)this)->SetTemporaryUnsummonedPetNumber(0);
8432 void Unit::SetInCombatWith(Unit
* enemy
)
8434 Unit
* eOwner
= enemy
->GetCharmerOrOwnerOrSelf();
8437 SetInCombatState(true);
8442 if(eOwner
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)eOwner
)->duel
)
8444 Unit
const* myOwner
= GetCharmerOrOwnerOrSelf();
8445 if(((Player
const*)eOwner
)->duel
->opponent
== myOwner
)
8447 SetInCombatState(true);
8451 SetInCombatState(false);
8454 void Unit::SetInCombatState(bool PvP
)
8456 // only alive units can be in combat
8461 m_CombatTimer
= 5000;
8462 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8464 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8465 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8468 void Unit::ClearInCombat()
8471 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
8473 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
8474 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
8476 // Player's state will be cleared in Player::UpdateContestedPvP
8477 if(GetTypeId()!=TYPEID_PLAYER
)
8478 clearUnitState(UNIT_STAT_ATTACK_PLAYER
);
8481 bool Unit::isTargetableForAttack() const
8483 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
8486 if(HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_NON_ATTACKABLE
| UNIT_FLAG_NOT_SELECTABLE
))
8489 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
8492 int32
Unit::ModifyHealth(int32 dVal
)
8499 int32 curHealth
= (int32
)GetHealth();
8501 int32 val
= dVal
+ curHealth
;
8508 int32 maxHealth
= (int32
)GetMaxHealth();
8513 gain
= val
- curHealth
;
8515 else if(curHealth
!= maxHealth
)
8517 SetHealth(maxHealth
);
8518 gain
= maxHealth
- curHealth
;
8524 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
8531 int32 curPower
= (int32
)GetPower(power
);
8533 int32 val
= dVal
+ curPower
;
8540 int32 maxPower
= (int32
)GetMaxPower(power
);
8544 SetPower(power
,val
);
8545 gain
= val
- curPower
;
8547 else if(curPower
!= maxPower
)
8549 SetPower(power
,maxPower
);
8550 gain
= maxPower
- curPower
;
8556 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
, bool is3dDistance
) const
8561 // Always can see self
8565 // player visible for other player if not logout and at same transport
8566 // including case when player is out of world
8567 bool at_same_transport
=
8568 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
8569 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
8570 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
8571 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
8574 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
8577 // forbidden to seen (at GM respawn command)
8578 if(m_Visibility
==VISIBILITY_RESPAWN
)
8581 // always seen by owner
8582 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
8585 // Grid dead/alive checks
8586 if( u
->GetTypeId()==TYPEID_PLAYER
)
8588 // non visible at grid for any stealth state
8589 if(!IsVisibleInGridForPlayer((Player
*)u
))
8592 // if player is dead then he can't detect anyone in any cases
8598 // all dead creatures/players not visible for any creatures
8599 if(!u
->isAlive() || !isAlive())
8603 // different visible distance checks
8604 if(u
->isInFlight()) // what see player in flight
8606 // use object grey distance for all (only see objects any way)
8607 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8610 else if(!isAlive()) // distance for show body
8612 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
), is3dDistance
))
8615 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
8617 if(u
->GetTypeId()==TYPEID_PLAYER
)
8619 // Players far than max visible distance for player or not in our map are not visible too
8620 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8625 // Units far than max visible distance for creature or not in our map are not visible too
8626 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8630 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
8632 // Pet/charmed far than max visible distance for player or not in our map are not visible too
8633 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8636 else // distance for show creature
8638 // Units far than max visible distance for creature or not in our map are not visible too
8639 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
), is3dDistance
))
8643 // Visible units, always are visible for all units, except for units under invisibility
8644 if (m_Visibility
== VISIBILITY_ON
&& u
->m_invisibilityMask
==0)
8647 // GMs see any players, not higher GMs and all units
8648 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
8650 if(GetTypeId() == TYPEID_PLAYER
)
8651 return ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity();
8656 // non faction visibility non-breakable for non-GMs
8657 if (m_Visibility
== VISIBILITY_OFF
)
8661 bool invisible
= (m_invisibilityMask
!= 0 || u
->m_invisibilityMask
!=0);
8663 // detectable invisibility case
8665 // Invisible units, always are visible for units under same invisibility type
8666 (m_invisibilityMask
& u
->m_invisibilityMask
)!=0 ||
8667 // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect)
8668 u
->canDetectInvisibilityOf(this) ||
8669 // Units that can detect invisibility always are visible for units that can be detected
8670 canDetectInvisibilityOf(u
) ))
8675 // special cases for always overwrite invisibility/stealth
8676 if(invisible
|| m_Visibility
== VISIBILITY_GROUP_STEALTH
)
8679 if (!u
->IsHostileTo(this))
8681 // 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)
8682 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
8684 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
8687 // else apply same rules as for hostile case (detecting check for stealth)
8693 // Hunter mark functionality
8694 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
8695 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
8696 if((*iter
)->GetCasterGUID()==u
->GetGUID())
8699 // else apply detecting check for stealth
8702 // none other cases for detect invisibility, so invisible
8706 // else apply stealth detecting check
8709 // unit got in stealth in this moment and must ignore old detected state
8710 if (m_Visibility
== VISIBILITY_GROUP_NO_DETECT
)
8713 // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
8714 if (m_Visibility
!= VISIBILITY_GROUP_STEALTH
)
8717 // NOW ONLY STEALTH CASE
8719 // stealth and detected and visible for some seconds
8720 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->m_DetectInvTimer
> 300 && ((Player
*)u
)->HaveAtClient(this))
8723 //if in non-detect mode then invisible for unit
8729 // If is attacked then stealth is lost, some creature can use stealth too
8730 if( !getAttackers().empty() )
8733 // If there is collision rogue is seen regardless of level difference
8734 // TODO: check sizes in DB
8735 float distance
= GetDistance(u
);
8736 if (distance
< 0.24f
)
8739 //If a mob or player is stunned he will not be able to detect stealth
8740 if (u
->hasUnitState(UNIT_STAT_STUNNED
) && (u
!= this))
8743 // Creature can detect target only in aggro radius
8744 if(u
->GetTypeId() != TYPEID_PLAYER
)
8746 //Always invisible from back and out of aggro range
8747 bool isInFront
= u
->isInFront(this,((Creature
const*)u
)->GetAttackDistance(this));
8753 //Always invisible from back
8754 bool isInFront
= u
->isInFront(this,(GetTypeId()==TYPEID_PLAYER
|| GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature());
8759 // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los
8760 if(!u
->HasAuraType(SPELL_AURA_DETECT_STEALTH
))
8762 //Calculation if target is in front
8764 //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
8765 float visibleDistance
= 10.5f
- (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH
)/100.0f
);
8767 //Visible distance is modified by
8768 //-Level Diff (every level diff = 1.0f in visible distance)
8769 visibleDistance
+= int32(u
->getLevelForTarget(this)) - int32(getLevelForTarget(u
));
8771 //This allows to check talent tree and will add addition stealth dependent on used points)
8772 int32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
8776 //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
8777 //based on wowwiki every 5 mod we have 1 more level diff in calculation
8778 visibleDistance
+= (int32(u
->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT
)) - stealthMod
)/5.0f
;
8780 if(distance
> visibleDistance
)
8784 // Now check is target visible with LoS
8786 u
->GetPosition(ox
,oy
,oz
);
8787 return IsWithinLOS(ox
,oy
,oz
);
8790 void Unit::SetVisibility(UnitVisibility x
)
8798 if(GetTypeId()==TYPEID_PLAYER
)
8799 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8801 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
8805 bool Unit::canDetectInvisibilityOf(Unit
const* u
) const
8807 if(uint32 mask
= (m_detectInvisibilityMask
& u
->m_invisibilityMask
))
8809 for(uint32 i
= 0; i
< 10; ++i
)
8811 if(((1 << i
) & mask
)==0)
8814 // find invisibility level
8815 uint32 invLevel
= 0;
8816 Unit::AuraList
const& iAuras
= u
->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY
);
8817 for(Unit::AuraList::const_iterator itr
= iAuras
.begin(); itr
!= iAuras
.end(); ++itr
)
8818 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& invLevel
< (*itr
)->GetModifier()->m_amount
)
8819 invLevel
= (*itr
)->GetModifier()->m_amount
;
8821 // find invisibility detect level
8822 uint32 detectLevel
= 0;
8823 Unit::AuraList
const& dAuras
= GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION
);
8824 for(Unit::AuraList::const_iterator itr
= dAuras
.begin(); itr
!= dAuras
.end(); ++itr
)
8825 if(((*itr
)->GetModifier()->m_miscvalue
)==i
&& detectLevel
< (*itr
)->GetModifier()->m_amount
)
8826 detectLevel
= (*itr
)->GetModifier()->m_amount
;
8828 if(i
==6 && GetTypeId()==TYPEID_PLAYER
) // special drunk detection case
8830 detectLevel
= ((Player
*)this)->GetDrunkValue();
8833 if(invLevel
<= detectLevel
)
8841 void Unit::UpdateSpeed(UnitMoveType mtype
, bool forced
)
8843 int32 main_speed_mod
= 0;
8844 float stack_bonus
= 1.0f
;
8845 float non_stack_bonus
= 1.0f
;
8853 if (IsMounted()) // Use on mount auras
8855 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
);
8856 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
);
8857 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
))/100.0f
;
8861 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SPEED
);
8862 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS
);
8863 non_stack_bonus
= (100.0f
+ GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK
))/100.0f
;
8871 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED
);
8874 case MOVE_SWIM_BACK
:
8878 if (IsMounted()) // Use on mount auras
8879 main_speed_mod
= GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
);
8880 else // Use not mount (shapeshift for example) auras (should stack)
8881 main_speed_mod
= GetTotalAuraModifier(SPELL_AURA_MOD_SPEED_FLIGHT
);
8882 stack_bonus
= GetTotalAuraMultiplier(SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
);
8883 non_stack_bonus
= (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
))/100.0f
;
8886 case MOVE_FLIGHT_BACK
:
8889 sLog
.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype
);
8893 float bonus
= non_stack_bonus
> stack_bonus
? non_stack_bonus
: stack_bonus
;
8894 // now we ready for speed calculation
8895 float speed
= main_speed_mod
? bonus
*(100.0f
+ main_speed_mod
)/100.0f
: bonus
;
8903 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8904 // TODO: possible affect only on MOVE_RUN
8905 if(int32 normalization
= GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
))
8907 // Use speed from aura
8908 float max_speed
= normalization
/ baseMoveSpeed
[mtype
];
8909 if (speed
> max_speed
)
8918 // Apply strongest slow aura mod to speed
8919 int32 slow
= GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED
);
8921 speed
*=(100.0f
+ slow
)/100.0f
;
8922 SetSpeed(mtype
, speed
, forced
);
8925 float Unit::GetSpeed( UnitMoveType mtype
) const
8927 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
8930 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
8935 // Update speed only on change
8936 if (m_speed_rate
[mtype
] == rate
)
8939 m_speed_rate
[mtype
] = rate
;
8941 propagateSpeedChange();
8949 data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8952 data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8955 data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8958 data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8960 case MOVE_SWIM_BACK
:
8961 data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8963 case MOVE_TURN_RATE
:
8964 data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 8+4+2+4+4+4+4+4+4+4);
8967 data
.Initialize(MSG_MOVE_SET_FLIGHT_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8969 case MOVE_FLIGHT_BACK
:
8970 data
.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED
, 8+4+2+4+4+4+4+4+4+4);
8972 case MOVE_PITCH_RATE
:
8973 data
.Initialize(MSG_MOVE_SET_PITCH_RATE
, 8+4+2+4+4+4+4+4+4+4);
8976 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
8980 data
.append(GetPackGUID());
8981 data
<< uint32(0); // movement flags
8982 data
<< uint16(0); // unk flags
8983 data
<< uint32(getMSTime());
8984 data
<< float(GetPositionX());
8985 data
<< float(GetPositionY());
8986 data
<< float(GetPositionZ());
8987 data
<< float(GetOrientation());
8988 data
<< uint32(0); // fall time
8989 data
<< float(GetSpeed(mtype
));
8990 SendMessageToSet( &data
, true );
8994 if(GetTypeId() == TYPEID_PLAYER
)
8996 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8997 // and do it only for real sent packets and use run for run/mounted as client expected
8998 ++((Player
*)this)->m_forced_speed_changes
[mtype
];
9004 data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16);
9007 data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 17);
9010 data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16);
9013 data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16);
9015 case MOVE_SWIM_BACK
:
9016 data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16);
9018 case MOVE_TURN_RATE
:
9019 data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16);
9022 data
.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE
, 16);
9024 case MOVE_FLIGHT_BACK
:
9025 data
.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE
, 16);
9027 case MOVE_PITCH_RATE
:
9028 data
.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE
, 16);
9031 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
9034 data
.append(GetPackGUID());
9035 data
<< (uint32
)0; // moveEvent, NUM_PMOVE_EVTS = 0x39
9036 if (mtype
== MOVE_RUN
)
9037 data
<< uint8(0); // new 2.1.0
9038 data
<< float(GetSpeed(mtype
));
9039 SendMessageToSet( &data
, true );
9041 if(Pet
* pet
= GetPet())
9042 pet
->SetSpeed(MOVE_RUN
, m_speed_rate
[mtype
],forced
);
9045 void Unit::SetHover(bool on
)
9048 CastSpell(this,11010,true);
9050 RemoveAurasDueToSpell(11010);
9053 void Unit::setDeathState(DeathState s
)
9055 if (s
!= ALIVE
&& s
!= JUST_ALIVED
)
9059 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
9061 if(IsNonMeleeSpellCasted(false))
9062 InterruptNonMeleeSpells(false);
9067 RemoveAllAurasOnDeath();
9068 UnsummonAllTotems();
9070 ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT
, false);
9071 ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT
, false);
9072 // remove aurastates allowing special moves
9073 ClearAllReactives();
9074 ClearDiminishings();
9076 else if(s
== JUST_ALIVED
)
9078 RemoveFlag (UNIT_FIELD_FLAGS
, UNIT_FLAG_SKINNABLE
); // clear skinnable for creature and player (at battleground)
9081 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
9083 //_ApplyAllAuraMods();
9088 /*########################################
9090 ######## AGGRO SYSTEM ########
9092 ########################################*/
9093 bool Unit::CanHaveThreatList() const
9095 // only creatures can have threat list
9096 if( GetTypeId() != TYPEID_UNIT
)
9099 // only alive units can have threat list
9103 // pets and totems can not have threat list
9104 if( ((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem() || ((Creature
*)this)->isVehicle() )
9110 //======================================================================
9112 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchoolMask schoolMask
)
9114 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
9117 SpellSchools school
= GetFirstSchoolInMask(schoolMask
);
9119 return threat
* m_threatModifier
[school
];
9122 //======================================================================
9124 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchoolMask schoolMask
, SpellEntry
const *threatSpell
)
9126 // Only mobs can manage threat lists
9127 if(CanHaveThreatList())
9128 m_ThreatManager
.addThreat(pVictim
, threat
, schoolMask
, threatSpell
);
9131 //======================================================================
9133 void Unit::DeleteThreatList()
9135 m_ThreatManager
.clearReferences();
9138 //======================================================================
9140 void Unit::TauntApply(Unit
* taunter
)
9142 assert(GetTypeId()== TYPEID_UNIT
);
9144 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9147 if(!CanHaveThreatList())
9150 Unit
*target
= getVictim();
9151 if(target
&& target
== taunter
)
9154 SetInFront(taunter
);
9155 if (((Creature
*)this)->AI())
9156 ((Creature
*)this)->AI()->AttackStart(taunter
);
9158 m_ThreatManager
.tauntApply(taunter
);
9161 //======================================================================
9163 void Unit::TauntFadeOut(Unit
*taunter
)
9165 assert(GetTypeId()== TYPEID_UNIT
);
9167 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
9170 if(!CanHaveThreatList())
9173 Unit
*target
= getVictim();
9174 if(!target
|| target
!= taunter
)
9177 if(m_ThreatManager
.isThreatListEmpty())
9179 if(((Creature
*)this)->AI())
9180 ((Creature
*)this)->AI()->EnterEvadeMode();
9184 m_ThreatManager
.tauntFadeOut(taunter
);
9185 target
= m_ThreatManager
.getHostilTarget();
9187 if (target
&& target
!= taunter
)
9190 if (((Creature
*)this)->AI())
9191 ((Creature
*)this)->AI()->AttackStart(target
);
9195 //======================================================================
9197 bool Unit::SelectHostilTarget()
9199 //function provides main threat functionality
9200 //next-victim-selection algorithm and evade mode are called
9201 //threat list sorting etc.
9203 assert(GetTypeId()== TYPEID_UNIT
);
9204 Unit
* target
= NULL
;
9206 //This function only useful once AI has been initialized
9207 if (!((Creature
*)this)->AI())
9210 if(!m_ThreatManager
.isThreatListEmpty())
9212 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
9214 target
= m_ThreatManager
.getHostilTarget();
9220 if(!hasUnitState(UNIT_STAT_STUNNED
))
9222 ((Creature
*)this)->AI()->AttackStart(target
);
9226 // no target but something prevent go to evade mode
9227 if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT
) )
9230 // last case when creature don't must go to evade mode:
9231 // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
9232 // for example at owner command to pet attack some far away creature
9233 // Note: creature not have targeted movement generator but have attacker in this case
9234 if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE
)
9236 for(AttackerSet::const_iterator itr
= m_attackers
.begin(); itr
!= m_attackers
.end(); ++itr
)
9238 if( (*itr
)->IsInMap(this) && (*itr
)->isTargetableForAttack() && (*itr
)->isInAccessablePlaceFor((Creature
*)this) )
9243 // enter in evade mode in other case
9244 ((Creature
*)this)->AI()->EnterEvadeMode();
9249 //======================================================================
9250 //======================================================================
9251 //======================================================================
9253 int32
Unit::CalculateSpellDamage(SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
, Unit
const* target
)
9255 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9257 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9259 int32 level
= int32(getLevel()) - int32(spellProto
->spellLevel
);
9260 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
9261 level
= spellProto
->maxLevel
;
9263 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
9264 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
9265 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
9266 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
9267 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
9269 // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell
9270 int32 randvalue
= spellProto
->EffectBaseDice
[effect_index
] >= randomPoints
? spellProto
->EffectBaseDice
[effect_index
]:irand(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
9271 int32 value
= basePoints
+ randvalue
;
9273 if(comboDamage
!= 0 && unitPlayer
&& target
&& (target
->GetGUID() == unitPlayer
->GetComboTarget()))
9274 value
+= (int32
)(comboDamage
* comboPoints
);
9276 if(Player
* modOwner
= GetSpellModOwner())
9278 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
9279 switch(effect_index
)
9282 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
9285 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
9288 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
9293 if(spellProto
->Attributes
& SPELL_ATTR_LEVEL_DAMAGE_CALCULATION
&& spellProto
->spellLevel
&&
9294 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&&
9295 spellProto
->Effect
[effect_index
] != SPELL_EFFECT_KNOCK_BACK
)
9296 value
= int32(value
*0.25f
*exp(getLevel()*(70-spellProto
->spellLevel
)/1000.0f
));
9301 int32
Unit::CalculateSpellDuration(SpellEntry
const* spellProto
, uint8 effect_index
, Unit
const* target
)
9303 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
9305 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
9307 int32 minduration
= GetSpellDuration(spellProto
);
9308 int32 maxduration
= GetSpellMaxDuration(spellProto
);
9312 if( minduration
!= -1 && minduration
!= maxduration
)
9313 duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
9315 duration
= minduration
;
9319 int32 mechanic
= GetEffectMechanic(spellProto
, effect_index
);
9320 // Find total mod value (negative bonus)
9321 int32 durationMod_always
= target
->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD
, mechanic
);
9322 // Find max mod (negative bonus)
9323 int32 durationMod_not_stack
= target
->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
, mechanic
);
9325 int32 durationMod
= 0;
9326 // Select strongest negative mod
9327 if (durationMod_always
> durationMod_not_stack
)
9328 durationMod
= durationMod_not_stack
;
9330 durationMod
= durationMod_always
;
9332 if (durationMod
!= 0)
9333 duration
= int32(int64(duration
) * (100+durationMod
) /100);
9335 if (duration
< 0) duration
= 0;
9341 DiminishingLevels
Unit::GetDiminishing(DiminishingGroup group
)
9343 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9345 if(i
->DRGroup
!= group
)
9349 return DIMINISHING_LEVEL_1
;
9352 return DIMINISHING_LEVEL_1
;
9354 // If last spell was casted more than 15 seconds ago - reset the count.
9355 if(i
->stack
==0 && getMSTimeDiff(i
->hitTime
,getMSTime()) > 15000)
9357 i
->hitCount
= DIMINISHING_LEVEL_1
;
9358 return DIMINISHING_LEVEL_1
;
9360 // or else increase the count.
9363 return DiminishingLevels(i
->hitCount
);
9366 return DIMINISHING_LEVEL_1
;
9369 void Unit::IncrDiminishing(DiminishingGroup group
)
9371 // Checking for existing in the table
9372 bool IsExist
= false;
9373 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9375 if(i
->DRGroup
!= group
)
9379 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
9386 m_Diminishing
.push_back(DiminishingReturn(group
,getMSTime(),DIMINISHING_LEVEL_2
));
9389 void Unit::ApplyDiminishingToDuration(DiminishingGroup group
, int32
&duration
,Unit
* caster
,DiminishingLevels Level
)
9391 if(duration
== -1 || group
== DIMINISHING_NONE
|| caster
->IsFriendlyTo(this) )
9394 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
9395 if(duration
> 10000 && IsDiminishingReturnsGroupDurationLimited(group
))
9397 // test pet/charm masters instead pets/charmeds
9398 Unit
const* targetOwner
= GetCharmerOrOwner();
9399 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
9401 Unit
const* target
= targetOwner
? targetOwner
: this;
9402 Unit
const* source
= casterOwner
? casterOwner
: caster
;
9404 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
9410 // Some diminishings applies to mobs too (for example, Stun)
9411 if((GetDiminishingReturnsGroupType(group
) == DRTYPE_PLAYER
&& GetTypeId() == TYPEID_PLAYER
) || GetDiminishingReturnsGroupType(group
) == DRTYPE_ALL
)
9413 DiminishingLevels diminish
= Level
;
9416 case DIMINISHING_LEVEL_1
: break;
9417 case DIMINISHING_LEVEL_2
: mod
= 0.5f
; break;
9418 case DIMINISHING_LEVEL_3
: mod
= 0.25f
; break;
9419 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
;break;
9424 duration
= int32(duration
* mod
);
9427 void Unit::ApplyDiminishingAura( DiminishingGroup group
, bool apply
)
9429 // Checking for existing in the table
9430 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
9432 if(i
->DRGroup
!= group
)
9435 i
->hitTime
= getMSTime();
9446 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
9448 return ObjectAccessor::GetUnit(object
,guid
);
9451 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
9453 return isVisibleForOrDetect(u
, false, inVisibleList
, false);
9456 uint32
Unit::GetCreatureType() const
9458 if(GetTypeId() == TYPEID_PLAYER
)
9460 SpellShapeshiftEntry
const* ssEntry
= sSpellShapeshiftStore
.LookupEntry(((Player
*)this)->m_form
);
9461 if(ssEntry
&& ssEntry
->creatureType
> 0)
9462 return ssEntry
->creatureType
;
9464 return CREATURE_TYPE_HUMANOID
;
9467 return ((Creature
*)this)->GetCreatureInfo()->type
;
9470 /*#######################################
9472 ######## STAT SYSTEM ########
9474 #######################################*/
9476 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
9478 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9480 sLog
.outError("ERROR in HandleStatModifier(): non existed UnitMods or wrong UnitModifierType!");
9486 switch(modifierType
)
9490 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
9494 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
9497 val
= (100.0f
+ amount
) / 100.0f
;
9498 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
9505 if(!CanModifyStats())
9510 case UNIT_MOD_STAT_STRENGTH
:
9511 case UNIT_MOD_STAT_AGILITY
:
9512 case UNIT_MOD_STAT_STAMINA
:
9513 case UNIT_MOD_STAT_INTELLECT
:
9514 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
9516 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
9517 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
9521 case UNIT_MOD_FOCUS
:
9522 case UNIT_MOD_ENERGY
:
9523 case UNIT_MOD_HAPPINESS
:
9525 case UNIT_MOD_RUNIC_POWER
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
9527 case UNIT_MOD_RESISTANCE_HOLY
:
9528 case UNIT_MOD_RESISTANCE_FIRE
:
9529 case UNIT_MOD_RESISTANCE_NATURE
:
9530 case UNIT_MOD_RESISTANCE_FROST
:
9531 case UNIT_MOD_RESISTANCE_SHADOW
:
9532 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
9534 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
9535 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
9537 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
9538 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
9539 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
9548 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
9550 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
9552 sLog
.outError("ERROR: trial to access non existed modifier value from UnitMods!");
9556 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
9559 return m_auraModifiersGroup
[unitMod
][modifierType
];
9562 float Unit::GetTotalStatValue(Stats stat
) const
9564 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
9566 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9569 // value = ((base_value * base_pct) + total_value) * total_pct
9570 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
9571 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9572 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9573 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9578 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
9580 if(unitMod
>= UNIT_MOD_END
)
9582 sLog
.outError("ERROR: trial to access non existed UnitMods in GetTotalAuraModValue()!");
9586 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
9589 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
9590 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
9591 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
9592 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
9597 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
9599 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
9603 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
9604 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
9605 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
9606 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
9607 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
9608 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
9617 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
9619 Stats stat
= STAT_STRENGTH
;
9623 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
9624 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
9625 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
9626 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
9627 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
9636 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
9640 case UNIT_MOD_MANA
: return POWER_MANA
;
9641 case UNIT_MOD_RAGE
: return POWER_RAGE
;
9642 case UNIT_MOD_FOCUS
: return POWER_FOCUS
;
9643 case UNIT_MOD_ENERGY
: return POWER_ENERGY
;
9644 case UNIT_MOD_HAPPINESS
: return POWER_HAPPINESS
;
9645 case UNIT_MOD_RUNE
: return POWER_RUNE
;
9646 case UNIT_MOD_RUNIC_POWER
:return POWER_RUNIC_POWER
;
9652 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
9654 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
9656 float val
= GetTotalAuraModValue(unitMod
);
9663 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
9665 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
9668 return m_weaponDamage
[attType
][type
];
9671 void Unit::SetLevel(uint32 lvl
)
9673 SetUInt32Value(UNIT_FIELD_LEVEL
, lvl
);
9676 if ((GetTypeId() == TYPEID_PLAYER
) && ((Player
*)this)->GetGroup())
9677 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
9680 void Unit::SetHealth(uint32 val
)
9682 uint32 maxHealth
= GetMaxHealth();
9686 SetUInt32Value(UNIT_FIELD_HEALTH
, val
);
9689 if(GetTypeId() == TYPEID_PLAYER
)
9691 if(((Player
*)this)->GetGroup())
9692 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
9694 else if(((Creature
*)this)->isPet())
9696 Pet
*pet
= ((Pet
*)this);
9697 if(pet
->isControlled())
9699 Unit
*owner
= GetOwner();
9700 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9701 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP
);
9706 void Unit::SetMaxHealth(uint32 val
)
9708 uint32 health
= GetHealth();
9709 SetUInt32Value(UNIT_FIELD_MAXHEALTH
, val
);
9712 if(GetTypeId() == TYPEID_PLAYER
)
9714 if(((Player
*)this)->GetGroup())
9715 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
9717 else if(((Creature
*)this)->isPet())
9719 Pet
*pet
= ((Pet
*)this);
9720 if(pet
->isControlled())
9722 Unit
*owner
= GetOwner();
9723 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9724 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP
);
9732 void Unit::SetPower(Powers power
, uint32 val
)
9734 if(GetPower(power
) == val
)
9737 uint32 maxPower
= GetMaxPower(power
);
9741 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
, val
);
9743 WorldPacket
data(SMSG_POWER_UPDATE
);
9744 data
.append(GetPackGUID());
9745 data
<< uint8(power
);
9746 data
<< uint32(val
);
9747 SendMessageToSet(&data
, GetTypeId() == TYPEID_PLAYER
? true : false);
9750 if(GetTypeId() == TYPEID_PLAYER
)
9752 if(((Player
*)this)->GetGroup())
9753 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9755 else if(((Creature
*)this)->isPet())
9757 Pet
*pet
= ((Pet
*)this);
9758 if(pet
->isControlled())
9760 Unit
*owner
= GetOwner();
9761 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9762 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9765 // Update the pet's character sheet with happiness damage bonus
9766 if(pet
->getPetType() == HUNTER_PET
&& power
== POWER_HAPPINESS
)
9768 pet
->UpdateDamagePhysical(BASE_ATTACK
);
9773 void Unit::SetMaxPower(Powers power
, uint32 val
)
9775 uint32 cur_power
= GetPower(power
);
9776 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
, val
);
9779 if(GetTypeId() == TYPEID_PLAYER
)
9781 if(((Player
*)this)->GetGroup())
9782 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9784 else if(((Creature
*)this)->isPet())
9786 Pet
*pet
= ((Pet
*)this);
9787 if(pet
->isControlled())
9789 Unit
*owner
= GetOwner();
9790 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9791 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9796 SetPower(power
, val
);
9799 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
9801 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
9804 if(GetTypeId() == TYPEID_PLAYER
)
9806 if(((Player
*)this)->GetGroup())
9807 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
9809 else if(((Creature
*)this)->isPet())
9811 Pet
*pet
= ((Pet
*)this);
9812 if(pet
->isControlled())
9814 Unit
*owner
= GetOwner();
9815 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9816 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER
);
9821 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
9823 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
9826 if(GetTypeId() == TYPEID_PLAYER
)
9828 if(((Player
*)this)->GetGroup())
9829 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
9831 else if(((Creature
*)this)->isPet())
9833 Pet
*pet
= ((Pet
*)this);
9834 if(pet
->isControlled())
9836 Unit
*owner
= GetOwner();
9837 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
9838 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER
);
9843 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
9845 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
9847 tAuraProcTriggerDamage
.push_back(aura
);
9849 tAuraProcTriggerDamage
.remove(aura
);
9852 uint32
Unit::GetCreatePowers( Powers power
) const
9854 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
9857 case POWER_MANA
: return GetCreateMana();
9858 case POWER_RAGE
: return 1000;
9859 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
9860 case POWER_ENERGY
: return 100;
9861 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
9862 case POWER_RUNIC_POWER
: return 1000;
9868 void Unit::AddToWorld()
9870 Object::AddToWorld();
9873 void Unit::RemoveFromWorld()
9878 RemoveNotOwnSingleTargetAuras();
9881 Object::RemoveFromWorld();
9884 void Unit::CleanupsBeforeDelete()
9886 if(m_uint32Values
) // only for fully created object
9888 InterruptNonMeleeSpells(true);
9889 m_Events
.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
9891 ClearComboPointHolders();
9893 getHostilRefManager().setOnlineOfflineState(false);
9895 RemoveAllGameObjects();
9896 RemoveAllDynObjects();
9897 GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
9902 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
9905 m_charmInfo
= new CharmInfo(charm
);
9909 CharmInfo::CharmInfo(Unit
* unit
)
9910 : m_unit(unit
), m_CommandState(COMMAND_FOLLOW
), m_reactState(REACT_PASSIVE
), m_petnumber(0)
9912 for(int i
=0; i
<4; ++i
)
9914 m_charmspells
[i
].spellId
= 0;
9915 m_charmspells
[i
].active
= ACT_DISABLED
;
9919 void CharmInfo::InitPetActionBar()
9921 // the first 3 SpellOrActions are attack, follow and stay
9922 for(uint32 i
= 0; i
< 3; i
++)
9924 PetActionBar
[i
].Type
= ACT_COMMAND
;
9925 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
9927 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
9928 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
9930 for(uint32 i
=0; i
< 4; i
++)
9932 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
9933 PetActionBar
[i
+ 3].SpellOrAction
= 0;
9937 void CharmInfo::InitEmptyActionBar()
9939 for(uint32 x
= 1; x
< 10; ++x
)
9941 PetActionBar
[x
].Type
= ACT_PASSIVE
;
9942 PetActionBar
[x
].SpellOrAction
= 0;
9944 PetActionBar
[0].Type
= ACT_COMMAND
;
9945 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
9948 void CharmInfo::InitPossessCreateSpells()
9950 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
9953 InitEmptyActionBar(); //charm action bar
9955 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9957 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
9958 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
9960 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_PASSIVE
);
9964 void CharmInfo::InitCharmCreateSpells()
9966 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
9968 InitEmptyActionBar();
9974 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
9976 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
9977 m_charmspells
[x
].spellId
= spellId
;
9982 if (IsPassiveSpell(spellId
))
9984 m_unit
->CastSpell(m_unit
, spellId
, true);
9985 m_charmspells
[x
].active
= ACT_PASSIVE
;
9989 ActiveStates newstate
;
9990 bool onlyselfcast
= true;
9991 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
9993 if(!spellInfo
) onlyselfcast
= false;
9994 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
9996 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
9997 onlyselfcast
= false;
10000 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
10001 newstate
= ACT_DISABLED
;
10003 newstate
= ACT_PASSIVE
;
10005 AddSpellToAB(0, spellId
, newstate
);
10010 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
10012 for(uint8 i
= 0; i
< 10; i
++)
10014 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_PASSIVE
) && PetActionBar
[i
].SpellOrAction
== oldid
)
10016 PetActionBar
[i
].SpellOrAction
= newid
;
10019 if(newstate
== ACT_DECIDE
)
10020 PetActionBar
[i
].Type
= ACT_DISABLED
;
10022 PetActionBar
[i
].Type
= newstate
;
10031 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
10033 if(IsPassiveSpell(spellid
))
10036 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
10038 if(spellid
== m_charmspells
[x
].spellId
)
10040 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
10045 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
10047 m_petnumber
= petnumber
;
10049 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
10051 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
10054 bool Unit::isFrozen() const
10056 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
10057 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
10058 if( GetSpellSchoolMask((*i
)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST
)
10063 struct ProcTriggeredData
10065 ProcTriggeredData(Aura
* _triggeredByAura
, uint32 _cooldown
)
10066 : triggeredByAura(_triggeredByAura
),
10067 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex())),
10068 cooldown(_cooldown
)
10071 Aura
* triggeredByAura
; // triggred aura, can be invalidate at triggered aura proccessing
10072 Unit::spellEffectPair triggeredByAura_SpellPair
; // spell pair, used for re-find aura (by pointer comparison in range)
10073 uint32 cooldown
; // possible hidden cooldown
10076 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
10078 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
, SpellSchoolMask damageSchoolMask
)
10080 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
10082 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
10083 ProcTriggeredList procTriggered
;
10085 AuraList
const& auras
= GetAurasByType(*aur
);
10086 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10092 uint32 cooldown
; // returned at next line
10093 if(!IsTriggeredAtSpellProcEvent(i_aura
->GetSpellProto(), procSpell
, procFlag
,attType
,isVictim
,cooldown
))
10096 procTriggered
.push_back( ProcTriggeredData(i_aura
, cooldown
) );
10099 // Handle effects proceed this time
10100 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
10102 // Some auras can be deleted in function called in this loop (except first, ofc)
10103 // Until storing auras in std::multimap to hard check deleting by another way
10104 if(i
!= procTriggered
.begin())
10106 bool found
= false;
10107 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10108 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10109 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10111 if(itr
->second
==i
->triggeredByAura
)
10120 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
);
10121 sLog
.outError("It can be deleted one from early processed auras:");
10122 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
10123 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
10124 sLog
.outError(" <end of list>");
10129 /// this is aura triggering code call
10130 Aura
* triggeredByAura
= i
->triggeredByAura
;
10132 /// save charges existence before processing to prevent crash at access to deleted triggered aura after
10133 /// used in speedup code check before check aura existance.
10134 bool triggeredByAuraWithCharges
= triggeredByAura
->m_procCharges
> 0;
10136 /// success in event proccesing
10137 /// used in speedup code check before check aura existance.
10138 bool casted
= false;
10140 /// process triggered code
10143 case SPELL_AURA_PROC_TRIGGER_SPELL
:
10145 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)",
10146 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10147 casted
= HandleProcTriggerSpell(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
, attType
, i
->cooldown
);
10150 case SPELL_AURA_PROC_TRIGGER_DAMAGE
:
10152 uint32 triggered_damage
= triggeredByAura
->GetModifier()->m_amount
;
10153 sLog
.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)",
10154 triggered_damage
, (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10155 SpellNonMeleeDamageLog(pTarget
, triggeredByAura
->GetId(), triggered_damage
, true, true);
10159 case SPELL_AURA_DUMMY
:
10161 uint32 effect
= triggeredByAura
->GetEffIndex();
10162 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)",
10163 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10164 casted
= HandleDummyAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10167 case SPELL_AURA_PRAYER_OF_MENDING
:
10169 sLog
.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
10170 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10172 casted
= HandleMeandingAuraProc(triggeredByAura
);
10175 case SPELL_AURA_MOD_HASTE
:
10177 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)",
10178 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10179 casted
= HandleHasteAuraProc(pTarget
, damage
, triggeredByAura
, procSpell
, procFlag
,i
->cooldown
);
10182 case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
:
10184 // nothing do, just charges counter
10185 // but count only in case appropriate school damage
10186 casted
= triggeredByAura
->GetModifier()->m_miscvalue
& damageSchoolMask
;
10189 case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
:
10191 sLog
.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)",
10192 (isVictim
?"a victim's":"an attacker's"),triggeredByAura
->GetId());
10193 casted
= HandleOverrideClassScriptAuraProc(pTarget
, triggeredByAura
, procSpell
,i
->cooldown
);
10198 // nothing do, just charges counter
10204 /// Update charge (aura can be removed by triggers)
10205 if(casted
&& triggeredByAuraWithCharges
)
10207 /// need re-found aura (can be dropped by triggers)
10208 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
10209 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
10210 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
10212 if(itr
->second
== triggeredByAura
) // pointer still valid
10214 if(triggeredByAura
->m_procCharges
> 0)
10215 triggeredByAura
->m_procCharges
-= 1;
10217 triggeredByAura
->UpdateAuraCharges();
10224 /// Safely remove auras with zero charges
10225 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
10228 if((*i
)->m_procCharges
== 0)
10230 RemoveAurasDueToSpell((*i
)->GetId());
10231 next
= auras
.begin();
10237 SpellSchoolMask
Unit::GetMeleeDamageSchoolMask() const
10239 return SPELL_SCHOOL_MASK_NORMAL
;
10242 Player
* Unit::GetSpellModOwner()
10244 if(GetTypeId()==TYPEID_PLAYER
)
10245 return (Player
*)this;
10246 if(((Creature
*)this)->isPet() || ((Creature
*)this)->isTotem())
10248 Unit
* owner
= GetOwner();
10249 if(owner
&& owner
->GetTypeId()==TYPEID_PLAYER
)
10250 return (Player
*)owner
;
10255 ///----------Pet responses methods-----------------
10256 void Unit::SendPetCastFail(uint32 spellid
, uint8 msg
)
10258 Unit
*owner
= GetCharmerOrOwner();
10259 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10262 WorldPacket
data(SMSG_PET_CAST_FAILED
, (4+1));
10263 data
<< uint8(0); // cast count?
10264 data
<< uint32(spellid
);
10265 data
<< uint8(msg
);
10266 // uint32 for some reason
10267 // uint32 for some reason
10268 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10271 void Unit::SendPetActionFeedback (uint8 msg
)
10273 Unit
* owner
= GetOwner();
10274 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10277 WorldPacket
data(SMSG_PET_ACTION_FEEDBACK
, 1);
10278 data
<< uint8(msg
);
10279 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10282 void Unit::SendPetTalk (uint32 pettalk
)
10284 Unit
* owner
= GetOwner();
10285 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10288 WorldPacket
data(SMSG_PET_ACTION_SOUND
, 8+4);
10289 data
<< uint64(GetGUID());
10290 data
<< uint32(pettalk
);
10291 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10294 void Unit::SendPetSpellCooldown (uint32 spellid
, time_t cooltime
)
10296 Unit
* owner
= GetOwner();
10297 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10300 WorldPacket
data(SMSG_SPELL_COOLDOWN
, 8+1+4+4);
10301 data
<< uint64(GetGUID());
10302 data
<< uint8(0x0); // flags (0x1, 0x2)
10303 data
<< uint32(spellid
);
10304 data
<< uint32(cooltime
);
10306 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10309 void Unit::SendPetClearCooldown (uint32 spellid
)
10311 Unit
* owner
= GetOwner();
10312 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10315 WorldPacket
data(SMSG_CLEAR_COOLDOWN
, (4+8));
10316 data
<< uint32(spellid
);
10317 data
<< uint64(GetGUID());
10318 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10321 void Unit::SendPetAIReaction(uint64 guid
)
10323 Unit
* owner
= GetOwner();
10324 if(!owner
|| owner
->GetTypeId() != TYPEID_PLAYER
)
10327 WorldPacket
data(SMSG_AI_REACTION
, 12);
10328 data
<< uint64(guid
) << uint32(00000002);
10329 ((Player
*)owner
)->GetSession()->SendPacket(&data
);
10332 ///----------End of Pet responses methods----------
10334 void Unit::StopMoving()
10336 clearUnitState(UNIT_STAT_MOVING
);
10338 // send explicit stop packet
10339 // rely on vmaps here because for example stormwind is in air
10340 //float z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true);
10341 //if (fabs(GetPositionZ() - z) < 2.0f)
10342 // Relocate(GetPositionX(), GetPositionY(), z);
10343 Relocate(GetPositionX(), GetPositionY(),GetPositionZ());
10345 SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), 0, true, 0);
10347 // update position and orientation;
10349 BuildHeartBeatMsg(&data
);
10350 SendMessageToSet(&data
,false);
10353 void Unit::SetFeared(bool apply
, uint64 casterGUID
, uint32 spellID
)
10357 if(HasAuraType(SPELL_AURA_PREVENTS_FLEEING
))
10360 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10362 GetMotionMaster()->MovementExpired(false);
10363 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10365 Unit
* caster
= ObjectAccessor::GetUnit(*this,casterGUID
);
10367 GetMotionMaster()->MoveFleeing(caster
); // caster==NULL processed in MoveFleeing
10371 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_FLEEING
);
10373 GetMotionMaster()->MovementExpired(false);
10375 if( GetTypeId() != TYPEID_PLAYER
&& isAlive() )
10377 // restore appropriate movement generator
10379 GetMotionMaster()->MoveChase(getVictim());
10381 GetMotionMaster()->Initialize();
10383 // attack caster if can
10384 Unit
* caster
= ObjectAccessor::GetObjectInWorld(casterGUID
, (Unit
*)NULL
);
10385 if(caster
&& caster
!= getVictim() && ((Creature
*)this)->AI())
10386 ((Creature
*)this)->AI()->AttackStart(caster
);
10390 if (GetTypeId() == TYPEID_PLAYER
)
10391 ((Player
*)this)->SetClientControl(this, !apply
);
10394 void Unit::SetConfused(bool apply
, uint64 casterGUID
, uint32 spellID
)
10398 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10400 CastStop(GetGUID()==casterGUID
? spellID
: 0);
10402 GetMotionMaster()->MoveConfused();
10406 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_CONFUSED
);
10408 GetMotionMaster()->MovementExpired(false);
10410 if (GetTypeId() == TYPEID_UNIT
)
10412 // if in combat restore movement generator
10414 GetMotionMaster()->MoveChase(getVictim());
10418 if(GetTypeId() == TYPEID_PLAYER
)
10419 ((Player
*)this)->SetClientControl(this, !apply
);
10422 bool Unit::IsSitState() const
10424 uint8 s
= getStandState();
10425 return s
== PLAYER_STATE_SIT_CHAIR
|| s
== PLAYER_STATE_SIT_LOW_CHAIR
||
10426 s
== PLAYER_STATE_SIT_MEDIUM_CHAIR
|| s
== PLAYER_STATE_SIT_HIGH_CHAIR
||
10427 s
== PLAYER_STATE_SIT
;
10430 bool Unit::IsStandState() const
10432 uint8 s
= getStandState();
10433 return !IsSitState() && s
!= PLAYER_STATE_SLEEP
&& s
!= PLAYER_STATE_KNEEL
;
10436 void Unit::SetStandState(uint8 state
)
10438 SetByteValue(UNIT_FIELD_BYTES_1
, 0, state
);
10440 if (IsStandState())
10441 RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED
);
10443 if(GetTypeId()==TYPEID_PLAYER
)
10445 WorldPacket
data(SMSG_STANDSTATE_UPDATE
, 1);
10446 data
<< (uint8
)state
;
10447 ((Player
*)this)->GetSession()->SendPacket(&data
);
10451 bool Unit::IsPolymorphed() const
10453 return GetSpellSpecific(getTransForm())==SPELL_MAGE_POLYMORPH
;
10456 void Unit::SetDisplayId(uint32 modelId
)
10458 SetUInt32Value(UNIT_FIELD_DISPLAYID
, modelId
);
10460 if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10462 Pet
*pet
= ((Pet
*)this);
10463 if(!pet
->isControlled())
10465 Unit
*owner
= GetOwner();
10466 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10467 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID
);
10471 void Unit::ClearComboPointHolders()
10473 while(!m_ComboPointHolders
.empty())
10475 uint32 lowguid
= *m_ComboPointHolders
.begin();
10477 Player
* plr
= objmgr
.GetPlayer(MAKE_NEW_GUID(lowguid
, 0, HIGHGUID_PLAYER
));
10478 if(plr
&& plr
->GetComboTarget()==GetGUID()) // recheck for safe
10479 plr
->ClearComboPoints(); // remove also guid from m_ComboPointHolders;
10481 m_ComboPointHolders
.erase(lowguid
); // or remove manually
10485 void Unit::ClearAllReactives()
10488 for(int i
=0; i
< MAX_REACTIVE
; ++i
)
10489 m_reactiveTimer
[i
] = 0;
10491 if (HasAuraState( AURA_STATE_DEFENSE
))
10492 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10493 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_PARRY
))
10494 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10495 if (HasAuraState( AURA_STATE_CRIT
))
10496 ModifyAuraState(AURA_STATE_CRIT
, false);
10497 if (getClass() == CLASS_HUNTER
&& HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE
) )
10498 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10500 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10501 ((Player
*)this)->ClearComboPoints();
10504 void Unit::UpdateReactives( uint32 p_time
)
10506 for(int i
= 0; i
< MAX_REACTIVE
; ++i
)
10508 ReactiveType reactive
= ReactiveType(i
);
10510 if(!m_reactiveTimer
[reactive
])
10513 if ( m_reactiveTimer
[reactive
] <= p_time
)
10515 m_reactiveTimer
[reactive
] = 0;
10517 switch ( reactive
)
10519 case REACTIVE_DEFENSE
:
10520 if (HasAuraState(AURA_STATE_DEFENSE
))
10521 ModifyAuraState(AURA_STATE_DEFENSE
, false);
10523 case REACTIVE_HUNTER_PARRY
:
10524 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_PARRY
))
10525 ModifyAuraState(AURA_STATE_HUNTER_PARRY
, false);
10527 case REACTIVE_CRIT
:
10528 if (HasAuraState(AURA_STATE_CRIT
))
10529 ModifyAuraState(AURA_STATE_CRIT
, false);
10531 case REACTIVE_HUNTER_CRIT
:
10532 if ( getClass() == CLASS_HUNTER
&& HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
) )
10533 ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE
, false);
10535 case REACTIVE_OVERPOWER
:
10536 if(getClass() == CLASS_WARRIOR
&& GetTypeId() == TYPEID_PLAYER
)
10537 ((Player
*)this)->ClearComboPoints();
10545 m_reactiveTimer
[reactive
] -= p_time
;
10550 Unit
* Unit::SelectNearbyTarget() const
10552 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
10554 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
10555 cell
.SetNoCreate();
10557 std::list
<Unit
*> targets
;
10560 MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
u_check(this, this, ATTACK_DISTANCE
);
10561 MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
> searcher(targets
, u_check
);
10563 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, WorldTypeMapContainer
> world_unit_searcher(searcher
);
10564 TypeContainerVisitor
<MaNGOS::UnitListSearcher
<MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck
>, GridTypeMapContainer
> grid_unit_searcher(searcher
);
10566 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
10567 cell_lock
->Visit(cell_lock
, world_unit_searcher
, *GetMap());
10568 cell_lock
->Visit(cell_lock
, grid_unit_searcher
, *GetMap());
10571 // remove current target
10573 targets
.remove(getVictim());
10575 // remove not LoS targets
10576 for(std::list
<Unit
*>::iterator tIter
= targets
.begin(); tIter
!= targets
.end();)
10578 if(!IsWithinLOSInMap(*tIter
))
10580 std::list
<Unit
*>::iterator tIter2
= tIter
;
10582 targets
.erase(tIter2
);
10588 // no appropriate targets
10589 if(targets
.empty())
10593 uint32 rIdx
= urand(0,targets
.size()-1);
10594 std::list
<Unit
*>::const_iterator tcIter
= targets
.begin();
10595 for(uint32 i
= 0; i
< rIdx
; ++i
)
10601 void Unit::ApplyAttackTimePercentMod( WeaponAttackType att
,float val
, bool apply
)
10605 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], val
, !apply
);
10606 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,val
,!apply
);
10610 ApplyPercentModFloatVar(m_modAttackSpeedPct
[att
], -val
, apply
);
10611 ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME
+att
,-val
,apply
);
10615 void Unit::ApplyCastTimePercentMod(float val
, bool apply
)
10618 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,val
,!apply
);
10620 ApplyPercentModFloatValue(UNIT_MOD_CAST_SPEED
,-val
,apply
);
10623 uint32
Unit::GetCastingTimeForBonus( SpellEntry
const *spellProto
, DamageEffectType damagetype
, uint32 CastingTime
)
10625 // Not apply this to creature casted spells with casttime==0
10626 if(CastingTime
==0 && GetTypeId()==TYPEID_UNIT
&& !((Creature
*)this)->isPet())
10629 if (CastingTime
> 7000) CastingTime
= 7000;
10630 if (CastingTime
< 1500) CastingTime
= 1500;
10632 if(damagetype
== DOT
&& !IsChanneledSpell(spellProto
))
10633 CastingTime
= 3500;
10635 int32 overTime
= 0;
10637 bool DirectDamage
= false;
10638 bool AreaEffect
= false;
10640 for ( uint32 i
=0; i
<3;i
++)
10642 switch ( spellProto
->Effect
[i
] )
10644 case SPELL_EFFECT_SCHOOL_DAMAGE
:
10645 case SPELL_EFFECT_POWER_DRAIN
:
10646 case SPELL_EFFECT_HEALTH_LEECH
:
10647 case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
:
10648 case SPELL_EFFECT_POWER_BURN
:
10649 case SPELL_EFFECT_HEAL
:
10650 DirectDamage
= true;
10652 case SPELL_EFFECT_APPLY_AURA
:
10653 switch ( spellProto
->EffectApplyAuraName
[i
] )
10655 case SPELL_AURA_PERIODIC_DAMAGE
:
10656 case SPELL_AURA_PERIODIC_HEAL
:
10657 case SPELL_AURA_PERIODIC_LEECH
:
10658 if ( GetSpellDuration(spellProto
) )
10659 overTime
= GetSpellDuration(spellProto
);
10662 // -5% per additional effect
10670 if(IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetA
[i
])) || IsAreaEffectTarget(Targets(spellProto
->EffectImplicitTargetB
[i
])))
10674 // Combined Spells with Both Over Time and Direct Damage
10675 if ( overTime
> 0 && CastingTime
> 0 && DirectDamage
)
10677 // mainly for DoTs which are 3500 here otherwise
10678 uint32 OriginalCastTime
= GetSpellCastTime(spellProto
);
10679 if (OriginalCastTime
> 7000) OriginalCastTime
= 7000;
10680 if (OriginalCastTime
< 1500) OriginalCastTime
= 1500;
10681 // Portion to Over Time
10682 float PtOT
= (overTime
/ 15000.f
) / ((overTime
/ 15000.f
) + (OriginalCastTime
/ 3500.f
));
10684 if ( damagetype
== DOT
)
10685 CastingTime
= uint32(CastingTime
* PtOT
);
10686 else if ( PtOT
< 1.0f
)
10687 CastingTime
= uint32(CastingTime
* (1 - PtOT
));
10692 // Area Effect Spells receive only half of bonus
10696 // -5% of total per any additional effect
10697 for ( uint8 i
=0; i
<effects
; ++i
)
10699 if ( CastingTime
> 175 )
10701 CastingTime
-= 175;
10710 return CastingTime
;
10713 void Unit::UpdateAuraForGroup(uint8 slot
)
10715 if(GetTypeId() == TYPEID_PLAYER
)
10717 Player
* player
= (Player
*)this;
10718 if(player
->GetGroup())
10720 player
->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS
);
10721 player
->SetAuraUpdateMask(slot
);
10724 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
10726 Pet
*pet
= ((Pet
*)this);
10727 if(pet
->isControlled())
10729 Unit
*owner
= GetOwner();
10730 if(owner
&& (owner
->GetTypeId() == TYPEID_PLAYER
) && ((Player
*)owner
)->GetGroup())
10732 ((Player
*)owner
)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS
);
10733 pet
->SetAuraUpdateMask(slot
);
10739 float Unit::GetAPMultiplier(WeaponAttackType attType
, bool normalized
)
10741 if (!normalized
|| GetTypeId() != TYPEID_PLAYER
)
10742 return float(GetAttackTime(attType
))/1000.0f
;
10744 Item
*Weapon
= ((Player
*)this)->GetWeaponForAttack(attType
);
10746 return 2.4; // fist attack
10748 switch (Weapon
->GetProto()->InventoryType
)
10750 case INVTYPE_2HWEAPON
:
10752 case INVTYPE_RANGED
:
10753 case INVTYPE_RANGEDRIGHT
:
10754 case INVTYPE_THROWN
:
10756 case INVTYPE_WEAPON
:
10757 case INVTYPE_WEAPONMAINHAND
:
10758 case INVTYPE_WEAPONOFFHAND
:
10760 return Weapon
->GetProto()->SubClass
==ITEM_SUBCLASS_WEAPON_DAGGER
? 1.7 : 2.4;
10764 Aura
* Unit::GetDummyAura( uint32 spell_id
) const
10766 Unit::AuraList
const& mDummy
= GetAurasByType(SPELL_AURA_DUMMY
);
10767 for(Unit::AuraList::const_iterator itr
= mDummy
.begin(); itr
!= mDummy
.end(); ++itr
)
10768 if ((*itr
)->GetId() == spell_id
)
10774 bool Unit::IsUnderLastManaUseEffect() const
10776 return getMSTimeDiff(m_lastManaUse
,getMSTime()) < 5000;
10779 void Unit::SetContestedPvP(Player
*attackedPlayer
)
10781 Player
* player
= GetCharmerOrOwnerPlayerOrPlayerItself();
10783 if(!player
|| attackedPlayer
&& (attackedPlayer
== player
|| player
->duel
&& player
->duel
->opponent
== attackedPlayer
))
10786 player
->SetContestedPvPTimer(30000);
10787 if(!player
->hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10789 player
->addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10790 player
->SetFlag(PLAYER_FLAGS
, PLAYER_FLAGS_CONTESTED_PVP
);
10791 // call MoveInLineOfSight for nearby contested guards
10792 SetVisibility(GetVisibility());
10794 if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER
))
10796 addUnitState(UNIT_STAT_ATTACK_PLAYER
);
10797 // call MoveInLineOfSight for nearby contested guards
10798 SetVisibility(GetVisibility());
10802 void Unit::AddPetAura(PetAura
const* petSpell
)
10804 m_petAuras
.insert(petSpell
);
10805 if(Pet
* pet
= GetPet())
10806 pet
->CastPetAura(petSpell
);
10809 void Unit::RemovePetAura(PetAura
const* petSpell
)
10811 m_petAuras
.erase(petSpell
);
10812 if(Pet
* pet
= GetPet())
10813 pet
->RemoveAurasDueToSpell(petSpell
->GetAura(pet
->GetEntry()));
10816 Pet
* Unit::CreateTamedPetFrom(Creature
* creatureTarget
,uint32 spell_id
)
10818 Pet
* pet
= new Pet(HUNTER_PET
);
10820 if(!pet
->CreateBaseAtCreature(creatureTarget
))
10826 pet
->SetOwnerGUID(GetGUID());
10827 pet
->SetCreatorGUID(GetGUID());
10828 pet
->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE
, getFaction());
10829 pet
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spell_id
);
10831 uint32 level
= (creatureTarget
->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget
->getLevel();
10832 pet
->SetFreeTalentPoints(pet
->GetMaxTalentPointsForLevel(level
));
10834 if(!pet
->InitStatsForLevel(level
))
10836 sLog
.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget
->GetEntry());
10841 pet
->GetCharmInfo()->SetPetNumber(objmgr
.GeneratePetNumber(), true);
10842 // this enables pet details window (Shift+P)
10843 pet
->AIM_Initialize();
10844 pet
->InitPetCreateSpells();
10845 pet
->SetHealth(pet
->GetMaxHealth());
10850 bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry
const* spellProto
, SpellEntry
const* procSpell
, uint32 procFlag
, WeaponAttackType attType
, bool isVictim
, uint32
& cooldown
)
10852 SpellProcEventEntry
const * spellProcEvent
= spellmgr
.GetSpellProcEvent(spellProto
->Id
);
10854 if(!spellProcEvent
)
10856 // used to prevent spam in log about same non-handled spells
10857 static std::set
<uint32
> nonHandledSpellProcSet
;
10859 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
10861 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
10862 nonHandledSpellProcSet
.insert(spellProto
->Id
);
10865 // spell.dbc use totally different flags, that only can create problems if used.
10869 // Check spellProcEvent data requirements
10870 if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
10873 // Check if current equipment allows aura to proc
10874 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
)
10876 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
10878 Item
*item
= ((Player
*)this)->GetWeaponForAttack(attType
,true);
10880 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10883 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
10885 // Check if player is wearing shield
10886 Item
*item
= ((Player
*)this)->GetShield(true);
10887 if(!item
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
10892 float chance
= (float)spellProto
->procChance
;
10894 if(Player
* modOwner
= GetSpellModOwner())
10895 modOwner
->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
10897 if(!isVictim
&& spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
10899 uint32 WeaponSpeed
= GetAttackTime(attType
);
10900 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
10903 cooldown
= spellProcEvent
? spellProcEvent
->cooldown
: 0;
10904 return roll_chance_f(chance
);
10907 bool Unit::HandleMeandingAuraProc( Aura
* triggeredByAura
)
10909 // aura can be deleted at casts
10910 SpellEntry
const* spellProto
= triggeredByAura
->GetSpellProto();
10911 uint32 effIdx
= triggeredByAura
->GetEffIndex();
10912 int32 heal
= triggeredByAura
->GetModifier()->m_amount
;
10913 uint64 caster_guid
= triggeredByAura
->GetCasterGUID();
10916 int32 jumps
= triggeredByAura
->m_procCharges
-1;
10918 // current aura expire
10919 triggeredByAura
->m_procCharges
= 1; // will removed at next charges decrease
10921 // next target selection
10922 if(jumps
> 0 && GetTypeId()==TYPEID_PLAYER
&& IS_PLAYER_GUID(caster_guid
))
10925 if (spellProto
->EffectRadiusIndex
[effIdx
])
10926 radius
= GetSpellRadius(sSpellRadiusStore
.LookupEntry(spellProto
->EffectRadiusIndex
[effIdx
]));
10928 radius
= GetSpellMaxRange(sSpellRangeStore
.LookupEntry(spellProto
->rangeIndex
));
10930 if(Player
* caster
= ((Player
*)triggeredByAura
->GetCaster()))
10932 caster
->ApplySpellMod(spellProto
->Id
, SPELLMOD_RADIUS
, radius
,NULL
);
10934 if(Player
* target
= ((Player
*)this)->GetNextRandomRaidMember(radius
))
10936 // aura will applied from caster, but spell casted from current aura holder
10937 SpellModifier
*mod
= new SpellModifier
;
10938 mod
->op
= SPELLMOD_CHARGES
;
10939 mod
->value
= jumps
-5; // negative
10940 mod
->type
= SPELLMOD_FLAT
;
10941 mod
->spellId
= spellProto
->Id
;
10942 mod
->mask
= spellProto
->SpellFamilyFlags
;
10943 mod
->mask2
= spellProto
->SpellFamilyFlags2
;
10945 caster
->AddSpellMod(mod
, true);
10946 CastCustomSpell(target
,spellProto
->Id
,&heal
,NULL
,NULL
,true,NULL
,triggeredByAura
,caster
->GetGUID());
10947 caster
->AddSpellMod(mod
, false);
10953 CastCustomSpell(this,33110,&heal
,NULL
,NULL
,true,NULL
,NULL
,caster_guid
);
10957 void Unit::RemoveAurasAtChanneledTarget(SpellEntry
const* spellInfo
)
10959 uint64 target_guid
= GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT
);
10961 if(!IS_UNIT_GUID(target_guid
))
10964 Unit
* target
= ObjectAccessor::GetUnit(*this, target_guid
);
10968 for (AuraMap::iterator iter
= target
->GetAuras().begin(); iter
!= target
->GetAuras().end(); )
10970 if (iter
->second
->GetId() == spellInfo
->Id
&& iter
->second
->GetCasterGUID()==GetGUID())
10971 target
->RemoveAura(iter
);