2 * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
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"
32 #include "SpellAuras.h"
33 #include "MapManager.h"
34 #include "ObjectAccessor.h"
35 #include "CreatureAI.h"
40 #include "TemporarySummon.h"
41 #include "BattleGroundMgr.h"
45 float baseMoveSpeed
[MAX_MOVE_TYPE
] =
49 1.25f
, // MOVE_WALKBACK
50 4.722222f
, // MOVE_SWIM
51 4.5f
, // MOVE_SWIMBACK
52 3.141594f
, // MOVE_TURN
57 // auraTypes contains auras capable of proc'ing for attacker
58 static std::set
<uint32
> GenerateAttakerProcAuraTypes()
60 static std::set
<uint32
> auraTypes
;
61 auraTypes
.insert(SPELL_AURA_DUMMY
);
62 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
63 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
67 // auraTypes contains auras capable of proc'ing for attacker
68 static std::set
<uint32
> GenerateVictimProcAuraTypes()
70 static std::set
<uint32
> auraTypes
;
71 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_SPELL
);
72 auraTypes
.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE
);
73 auraTypes
.insert(SPELL_AURA_DUMMY
);
74 auraTypes
.insert(SPELL_AURA_MOD_PARRY_PERCENT
);
78 static std::set
<uint32
> attackerProcAuraTypes
= GenerateAttakerProcAuraTypes();
79 static std::set
<uint32
> victimProcAuraTypes
= GenerateVictimProcAuraTypes();
81 // auraTypes contains auras capable of proc'ing for attacker and victim
82 static std::set
<uint32
> GenerateProcAuraTypes()
84 static std::set
<uint32
> auraTypes
= victimProcAuraTypes
;
85 auraTypes
.insert(attackerProcAuraTypes
.begin(),attackerProcAuraTypes
.end());
89 static std::set
<uint32
> procAuraTypes
= GenerateProcAuraTypes();
91 bool IsPassiveStackableSpell( uint32 spellId
)
93 if(!IsPassiveSpell(spellId
))
96 SpellEntry
const* spellProto
= sSpellStore
.LookupEntry(spellId
);
100 for(int j
= 0; j
< 3; ++j
)
102 if(std::find(procAuraTypes
.begin(),procAuraTypes
.end(),spellProto
->EffectApplyAuraName
[j
])!=procAuraTypes
.end())
109 Unit::Unit( WorldObject
*instantiator
)
110 : WorldObject( instantiator
), m_ThreatManager(this), m_HostilRefManager(this)
112 m_objectType
|= TYPE_UNIT
;
113 m_objectTypeId
= TYPEID_UNIT
;
115 m_updateFlag
= (UPDATEFLAG_ALL
| UPDATEFLAG_LIVING
| UPDATEFLAG_HASPOSITION
);
117 m_attackTimer
[BASE_ATTACK
] = 0;
118 m_attackTimer
[OFF_ATTACK
] = 0;
119 m_attackTimer
[RANGED_ATTACK
] = 0;
120 m_modAttackSpeedPct
[BASE_ATTACK
] = 1.0f
;
121 m_modAttackSpeedPct
[OFF_ATTACK
] = 1.0f
;
122 m_modAttackSpeedPct
[RANGED_ATTACK
] = 1.0f
;
126 m_deathState
= ALIVE
;
128 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
129 m_currentSpells
[i
] = NULL
;
131 m_TotemSlot
[0] = m_TotemSlot
[1] = m_TotemSlot
[2] = m_TotemSlot
[3] = 0;
132 m_ObjectSlot
[0] = m_ObjectSlot
[1] = m_ObjectSlot
[2] = m_ObjectSlot
[3] = 0;
134 //m_AurasCheck = 2000;
135 //m_removeAuraTimer = 4;
140 m_Visibility
= VISIBILITY_ON
;
143 m_detectInvisibility
= 0;
145 m_invisibilityvalue
= 0;
147 m_ShapeShiftForm
= 0;
148 m_canModifyStats
= false;
150 for (int i
= 0; i
< TOTAL_AURAS
; i
++)
151 m_AuraModifiers
[i
] = 0;
152 for (int i
= 0; i
< IMMUNITY_MECHANIC
; i
++)
153 m_spellImmune
[i
].clear();
154 for (int i
= 0; i
< UNIT_MOD_END
; i
++)
156 m_auraModifiersGroup
[i
][BASE_VALUE
] = 0.0f
;
157 m_auraModifiersGroup
[i
][BASE_PCT
] = 1.0f
;
158 m_auraModifiersGroup
[i
][TOTAL_VALUE
] = 0.0f
;
159 m_auraModifiersGroup
[i
][TOTAL_PCT
] = 1.0f
;
161 // implement 50% base damage from offhand
162 m_auraModifiersGroup
[UNIT_MOD_DAMAGE_OFFHAND
][TOTAL_PCT
] = 0.5f
;
164 for (int i
= 0; i
< 3; i
++)
166 m_weaponDamage
[i
][MINDAMAGE
] = BASE_MINDAMAGE
;
167 m_weaponDamage
[i
][MAXDAMAGE
] = BASE_MAXDAMAGE
;
169 for (int i
= 0; i
< MAX_STATS
; i
++)
170 m_createStats
[i
] = 0.0f
;
174 m_modSpellHitChance
= 0;
175 m_baseSpellCritChance
= 5;
176 m_modResilience
= 0.0;
178 //m_victimThreat = 0.0f;
179 for (int i
= 0; i
< MAX_SPELL_SCHOOL
; ++i
)
180 m_threatModifier
[i
] = 1.0f
;
182 for (int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
183 m_speed_rate
[i
] = 1.0f
;
191 // set current spells as deletable
192 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
194 // spell may be safely deleted now
195 if (m_currentSpells
[i
]) m_currentSpells
[i
]->SetDeletable(true);
196 m_currentSpells
[i
] = NULL
;
199 // remove references to unit
200 for(std::list
<GameObject
*>::iterator i
= m_gameObj
.begin(); i
!= m_gameObj
.end();)
202 (*i
)->SetOwnerGUID(0);
203 (*i
)->SetRespawnTime(0);
205 i
= m_gameObj
.erase(i
);
208 RemoveAllDynObjects();
210 if(m_charmInfo
) delete m_charmInfo
;
213 void Unit::RemoveAllDynObjects()
215 while(!m_dynObjGUIDs
.empty())
217 DynamicObject
* dynObj
= ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
220 m_dynObjGUIDs
.erase(m_dynObjGUIDs
.begin());
224 void Unit::Update( uint32 p_time
)
226 /*if(p_time > m_AurasCheck)
231 m_AurasCheck -= p_time;*/
233 // WARNING! Order of execution here is important, do not change.
234 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
235 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
236 m_Events
.Update( p_time
);
237 _UpdateSpells( p_time
);
239 //update combat timer only for players and pets
240 if (isInCombat() && (GetTypeId() == TYPEID_PLAYER
|| ((Creature
*)this)->isPet() || ((Creature
*)this)->isCharmed()))
242 if(m_HostilRefManager
.isEmpty())
244 // m_CombatTimer set at aura start and it will be freeze until aura removing
245 if(!HasAuraType(SPELL_AURA_INTERRUPT_REGEN
))
247 if ( m_CombatTimer
<= p_time
)
250 m_CombatTimer
-= p_time
;
255 if(uint32 base_att
= getAttackTimer(BASE_ATTACK
))
257 setAttackTimer(BASE_ATTACK
, (p_time
>= base_att
? 0 : base_att
- p_time
) );
259 if(GetHealth() < GetMaxHealth()*0.2)
260 ModifyAuraState(AURA_STATE_HEALTHLESS
, true);
261 else ModifyAuraState(AURA_STATE_HEALTHLESS
, false);
264 bool Unit::haveOffhandWeapon() const
266 if(GetTypeId() == TYPEID_PLAYER
)
268 Item
*tmpitem
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
270 return tmpitem
&& !tmpitem
->IsBroken() && (tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPON
|| tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPONOFFHAND
);
276 void Unit::SendMoveToPacket(float x
, float y
, float z
, bool run
, uint32 transitTime
)
278 float dx
= x
- GetPositionX();
279 float dy
= y
- GetPositionY();
280 float dz
= z
- GetPositionZ();
283 float dist
= ((dx
*dx
) + (dy
*dy
) + (dz
*dz
));
288 double speed
= GetSpeed(run
? MOVE_RUN
: MOVE_WALK
);
292 transitTime
= static_cast<uint32
>(dist
/ speed
+ 0.5);
294 //float orientation = (float)atan2((double)dy, (double)dx);
295 SendMonsterMove(x
,y
,z
,0,run
,transitTime
);
298 void Unit::SendMonsterMove(float NewPosX
, float NewPosY
, float NewPosZ
, uint8 type
, bool Run
, uint32 Time
)
300 WorldPacket
data( SMSG_MONSTER_MOVE
, (41 + GetPackGUID().size()) );
301 data
.append(GetPackGUID());
303 // Point A, starting location
304 data
<< GetPositionX() << GetPositionY() << GetPositionZ();
305 // unknown field - unrelated to orientation
306 // seems to increment about 1000 for every 1.7 seconds
307 // for now, we'll just use mstime
310 data
<< uint8(type
); // unknown
313 case 0: // normal packet
315 case 1: // stop packet
316 SendMessageToSet( &data
, true );
318 case 3: // not used currently
319 data
<< uint64(0); // probably target guid
321 case 4: // not used currently
322 data
<< float(0); // probably orientation
326 data
<< uint32(Run
? 0x00000100 : 0x00000000); // flags (0x100 - running, 0x200 - taxi)
328 512: Floating, moving without walking/running
330 data
<< Time
; // Time in between points
331 data
<< uint32(1); // 1 single waypoint
332 data
<< NewPosX
<< NewPosY
<< NewPosZ
; // the single waypoint Point B
334 SendMessageToSet( &data
, true );
337 void Unit::resetAttackTimer(WeaponAttackType type
)
339 if (GetTypeId() == TYPEID_PLAYER
)
340 m_attackTimer
[type
] = uint32(GetAttackTime(type
) * m_modAttackSpeedPct
[type
]);
342 m_attackTimer
[type
] = uint32(BASE_ATTACK_TIME
* m_modAttackSpeedPct
[type
]);
345 bool Unit::canReachWithAttack(Unit
*pVictim
) const
348 float reach
= GetFloatValue(UNIT_FIELD_COMBATREACH
);
351 return IsWithinDistInMap(pVictim
, reach
);
354 void Unit::RemoveSpellsCausingAura(uint32 auraType
)
356 if (auraType
>= TOTAL_AURAS
) return;
357 AuraList::iterator iter
, next
;
358 for (iter
= m_modAuras
[auraType
].begin(); iter
!= m_modAuras
[auraType
].end(); iter
= next
)
365 RemoveAurasDueToSpell((*iter
)->GetId());
366 if (!m_modAuras
[auraType
].empty())
367 next
= m_modAuras
[auraType
].begin();
374 bool Unit::HasAuraType(uint32 auraType
) const
376 return (!m_modAuras
[auraType
].empty());
379 /* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
380 void Unit::RemoveSpellbyDamageTaken(uint32 auraType
, uint32 damage
)
382 if(!HasAuraType(auraType
))
385 // The chance to dispell an aura depends on the damage taken with respect to the casters level.
386 uint32 max_dmg
= getLevel() > 8 ? 25 * getLevel() - 150 : 50;
387 float chance
= float(damage
) / max_dmg
* 100.0;
388 if (roll_chance_f(chance
))
389 RemoveSpellsCausingAura(auraType
);
392 void Unit::DealDamage(Unit
*pVictim
, uint32 damage
, CleanDamage
const* cleanDamage
, DamageEffectType damagetype
, SpellSchools damageSchool
, SpellEntry
const *spellProto
, uint32 procFlag
, bool durabilityLoss
)
394 if (!pVictim
->isAlive() || pVictim
->isInFlight()) return;
396 //You don't lose health from damage taken from another player while in a sanctuary
397 //You still see it in the combat log though
398 if(pVictim
!= this && GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
400 const AreaTableEntry
*area
= GetAreaEntryByAreaID(pVictim
->GetAreaId());
401 if(area
&& area
->flags
& 0x800) //sanctuary
405 // remove affects at any damage (including 0 damage)
407 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
408 if(HasInvisibilityAura())
409 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
410 // remove death simulation at damage
411 if(hasUnitState(UNIT_STAT_DIED
))
412 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
414 //Script Event damage Deal
415 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
416 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
417 //Script Event damage taken
418 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
419 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
423 // Rage from physical damage received .
424 if(cleanDamage
&& cleanDamage
->damage
&& damageSchool
==SPELL_SCHOOL_NORMAL
&& pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
425 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
430 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
431 // root type spells do not dispell the root effect
432 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
433 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
435 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
437 //pVictim->SetInFront(this);
438 // no loot,xp,health if type 8 /critters/
439 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
441 pVictim
->setDeathState(JUST_DIED
);
442 pVictim
->SetHealth(0);
443 pVictim
->CombatStop(true);
444 pVictim
->DeleteThreatList();
447 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
448 ((Creature
*)pVictim
)->AI()->AttackStart(this);
451 DEBUG_LOG("DealDamageStart");
453 uint32 health
= pVictim
->GetHealth();
454 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
456 // duel ends when player has 1 or less hp
457 bool duel_hasEnded
= false;
458 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
460 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
461 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
464 duel_hasEnded
= true;
467 if(pVictim
!= this && damagetype
!= DOT
)
470 pVictim
->SetInCombat();
473 // Rage from Damage made (only from direct weapon damage)
474 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
476 uint32 weaponSpeedHitFactor
;
478 switch(cleanDamage
->attackType
)
482 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
483 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
485 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
487 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
493 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
494 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
496 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
498 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
507 if (health
<= damage
)
509 // battleground things
510 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
512 Player
*killed
= ((Player
*)pVictim
);
513 Player
*killer
= NULL
;
514 if(GetTypeId() == TYPEID_PLAYER
)
515 killer
= ((Player
*)this);
516 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
518 Unit
*owner
= GetOwner();
519 if(owner
->GetTypeId() == TYPEID_PLAYER
)
520 killer
= ((Player
*)owner
);
523 BattleGround
*bg
= sBattleGroundMgr
.GetBattleGround(killed
->GetBattleGroundId());
526 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
528 bg
->UpdatePlayerScore(killed
, SCORE_DEATHS
, 1);
531 bg
->UpdatePlayerScore(killer
, SCORE_KILLS
, 1);
535 DEBUG_LOG("DealDamage: victim just died");
537 DEBUG_LOG("DealDamageAttackStop");
539 pVictim
->CombatStop(true);
541 DEBUG_LOG("SET JUST_DIED");
542 pVictim
->setDeathState(JUST_DIED
);
544 DEBUG_LOG("DealDamageHealth1");
545 pVictim
->SetHealth(0);
547 // Call KilledUnit for creatures
548 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
549 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
551 // 10% durability loss on death
552 // clean InHateListOf
553 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
555 if (GetTypeId() != TYPEID_PLAYER
&& durabilityLoss
)
557 DEBUG_LOG("We are dead, loosing 10 percents durability");
558 ((Player
*)pVictim
)->DurabilityLossAll(0.10);
559 // durability lost message
560 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
561 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
563 pVictim
->getHostilRefManager().deleteReferences();
565 Pet
*pet
= pVictim
->GetPet();
566 if(pet
&& pVictim
->GetTypeId() != TYPEID_PLAYER
)
568 pet
->setDeathState(JUST_DIED
);
569 pet
->CombatStop(true);
571 pet
->addUnitState(UNIT_STAT_DIED
);
572 pet
->getHostilRefManager().deleteReferences();
575 else // creature died
577 DEBUG_LOG("DealDamageNotPlayer");
579 if(((Creature
*)pVictim
)->isPet())
580 pVictim
->getHostilRefManager().deleteReferences();
583 pVictim
->DeleteThreatList();
584 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
586 // Call creature just died function
587 if (((Creature
*)pVictim
)->AI())
588 ((Creature
*)pVictim
)->AI()->JustDied(this);
591 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
593 Player
*player
= NULL
;
595 if(GetTypeId() == TYPEID_PLAYER
)
597 player
= (Player
*)this;
598 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
603 if(player
->GetPetGUID() && (pet
= player
->GetPet()))
604 pet
->ClearInCombat();
606 if(player
->GetCharmGUID() && (pet
= player
->GetCharm()))
607 pet
->ClearInCombat();
609 // FIXME: or charmed (can be player). Maybe must be check before GetTypeId() == TYPEID_PLAYER
610 else if(GetCharmerOrOwnerGUID()) // Pet or timed creature, etc
613 Unit
* owner
= pet
->GetCharmerOrOwner();
615 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
617 player
= (Player
*)owner
;
618 player
->ClearInCombat();
619 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
623 if(pet
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pet
)->isPet())
625 uint32 petxp
= MaNGOS::XP::BaseGain(getLevel(), pVictim
->getLevel());
626 ((Pet
*)pet
)->GivePetXP(petxp
);
630 // self or owner of pet
635 // prepare data for near group iteration (PvP and !PvP cases
636 uint32 xp
= PvP
|| IsNoDamageXPArea(player
->GetAreaId()) ? 0 : MaNGOS::XP::Gain(player
, pVictim
);
637 bool honored_kill
= false;
639 Group
*pGroup
= player
->GetGroup();
642 uint32 count
= pGroup
->GetMemberCountForXPAtKill(pVictim
);
645 // skip in check PvP case (for speed, not used)
646 bool is_raid
= PvP
? false : MapManager::Instance().GetBaseMap(player
->GetMapId())->IsRaid() && pGroup
->isRaidGroup();
648 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
650 Player
*pGroupGuy
= pGroup
->GetMemberForXPAtKill(itr
->getSource(),pVictim
);
654 // honor can be in PvP and !PvP (racial leader) cases
655 if(pGroupGuy
->RewardHonor(pVictim
,count
) && player
==pGroupGuy
)
658 // xp and reputation only in !PvP case
661 // FIXME: xp/count for all in group at this moment, must be level dependent
662 float rate
= 1.0f
/count
;
664 // if with raid in raid dungeon then all receive full reputation at kill
665 pGroupGuy
->RewardReputation(pVictim
,is_raid
? 1.0f
: rate
);
667 uint32 itr_xp
= uint32(xp
*rate
);
669 pGroupGuy
->GiveXP(itr_xp
, pVictim
);
670 if(Pet
* pet
= player
->GetPet())
672 pet
->GivePetXP(itr_xp
/2);
675 // normal creature (not pet/etc) can be only in !PvP case
676 if(pVictim
->GetTypeId()==TYPEID_UNIT
)
677 pGroupGuy
->KilledMonster(pVictim
->GetEntry(), pVictim
->GetGUID());
684 // honor can be in PvP and !PvP (racial leader) cases
685 if(player
->RewardHonor(pVictim
,1))
688 // xp and reputation only in !PvP case
691 player
->RewardReputation(pVictim
,1);
692 player
->GiveXP(xp
, pVictim
);
693 if(Pet
* pet
= player
->GetPet())
698 // normal creature (not pet/etc) can be only in !PvP case
699 if(pVictim
->GetTypeId()==TYPEID_UNIT
)
700 player
->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
704 if(xp
|| honored_kill
)
705 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
710 DEBUG_LOG("Monster kill Monster");
713 // last damage from duel opponent or opponent controlled creature?
716 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
717 Player
*he
= (Player
*)pVictim
;
721 CombatStop(); // for case killed by pet
722 if (IsNonMeleeSpellCasted(true))
723 InterruptNonMeleeSpells(true);
724 if(he
->duel
->opponent
!=this)
726 he
->duel
->opponent
->CombatStop();
727 if(he
->duel
->opponent
->IsNonMeleeSpellCasted(true))
728 he
->duel
->opponent
->InterruptNonMeleeSpells(true);
731 if(he
->IsNonMeleeSpellCasted(true))
732 he
->InterruptNonMeleeSpells(true);
737 else // if (health <= damage)
739 DEBUG_LOG("DealDamageAlive");
741 pVictim
->ModifyHealth(- (int32
)damage
);
743 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
744 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
746 uint32 procVictim
= PROC_FLAG_NONE
;
748 // if just dropped below 20% (for CheatDeath)
749 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
750 procVictim
= PROC_FLAG_LOW_HEALTH
;
752 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
755 if(damagetype
!= DOT
)
757 //start melee attacks only after melee hit
758 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
761 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
763 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
764 pVictim
->setTransForm(0);
767 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
769 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
771 pVictim
->AddThreat(this, damage
, damageSchool
, spellProto
);
773 else // victim is a player
775 // Rage from damage received (only from physical damage)
776 if(damageSchool
==SPELL_SCHOOL_NORMAL
&& this != pVictim
&& pVictim
->GetTypeId() == TYPEID_PLAYER
&& pVictim
->getPowerType() == POWER_RAGE
)
778 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
779 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
782 // random durability for items (HIT)
783 if (urand(0,300) == 10)
785 DEBUG_LOG("HIT: We decrease durability with 5 percent");
786 ((Player
*)pVictim
)->DurabilityLossAll(0.05);
790 // TODO: Store auras by interrupt flag to speed this up.
791 AuraMap
& vAuras
= pVictim
->GetAuras();
792 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
794 const SpellEntry
*se
= i
->second
->GetSpellProto();
796 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
799 if (se
->procFlags
& (1<<3))
801 if (!roll_chance_i(se
->procChance
))
806 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
807 // FIXME: this may cause the auras with proc chance to be rerolled several times
808 next
= vAuras
.begin();
813 if (damagetype
!= NODAMAGE
)
815 if(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
] && pVictim
->GetTypeId() == TYPEID_PLAYER
&& damage
)
817 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_CASTING
)
819 uint32 channelInterruptFlags
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->ChannelInterruptFlags
;
820 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
822 sLog
.outDetail("Spell %u delayed (%d) at damage!",pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
,(int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
823 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->DelayedChannel((int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
825 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
827 sLog
.outDetail("Spell %u canceled at damage!",pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
);
828 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
831 else if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_DELAYED
)
832 // break channeled spell in delayed state on damage
834 sLog
.outDetail("Spell %u canceled at damage!",pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
);
835 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
840 // last damage from duel opponent
843 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
844 Player
*he
= (Player
*)pVictim
;
849 CombatStop(); // for case killed by pet
850 if(he
->duel
->opponent
!=this)
851 he
->duel
->opponent
->CombatStop();
854 he
->CastSpell(he
, 7267, true); // beg
859 DEBUG_LOG("DealDamageEnd");
862 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
864 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
868 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
872 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
875 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
879 sLog
.outError("WORLD: unknown spell ");
884 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
886 Spell
*spell
= new Spell(this, spellInfo
, triggered
, triggredByAura
,originalCaster
);
888 SpellCastTargets targets
;
889 targets
.setUnitTarget( Victim
);
890 spell
->m_CastItem
= castItem
;
891 spell
->prepare(&targets
);
894 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
896 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
900 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
904 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggredByAura
, originalCaster
);
907 void Unit::CastCustomSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
911 sLog
.outError("WORLD: unknown spell ");
916 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
918 Spell
*spell
= new Spell(this, spellInfo
, triggered
, triggredByAura
,originalCaster
);
921 spell
->m_currentBasePoints
[0] = *bp0
;
924 spell
->m_currentBasePoints
[1] = *bp1
;
927 spell
->m_currentBasePoints
[2] = *bp2
;
929 SpellCastTargets targets
;
930 targets
.setUnitTarget( Victim
);
931 spell
->m_CastItem
= castItem
;
932 spell
->prepare(&targets
);
935 void Unit::DealDamageBySchool(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
938 // TODO this in only generic way, check for exceptions
939 DEBUG_LOG("DealDamageBySchool (BEFORE) SCHOOL %u >> DMG:%u", spellInfo
->School
, *damage
);
942 switch (spellInfo
->School
)
944 // Physical damage school
945 case SPELL_SCHOOL_NORMAL
:
947 // Calculate physical outcome
948 MeleeHitOutcome outcome
;
949 outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
951 //Used to store the Hit Outcome
952 cleanDamage
->hitOutCome
= outcome
;
954 // Return miss first (sends miss message)
955 if(outcome
== MELEE_HIT_MISS
)
957 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
960 if(GetTypeId()== TYPEID_PLAYER
)
961 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
963 CastMeleeProcDamageAndSpell(pVictim
,0,BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
967 // Hitinfo, Victimstate
968 uint32 hitInfo
, victimState
;
969 hitInfo
= HITINFO_NORMALSWING
;
971 //Calculate armor mitigation
972 uint32 damageAfterArmor
;
973 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
974 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
975 *damage
= damageAfterArmor
;
983 // Resilience - reduce crit damage by 2x%
984 uint32 resilienceReduction
= uint32(pVictim
->m_modResilience
* 2/100 * (*damage
));
985 cleanDamage
->damage
+= resilienceReduction
;
986 *damage
-= resilienceReduction
;
988 hitInfo
|= HITINFO_CRITICALHIT
;
991 case MELEE_HIT_PARRY
:
993 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
995 victimState
= VICTIMSTATE_PARRY
;
997 // Counter-attack ( explained in Unit::DoAttackDamage() )
1000 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1001 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1003 // Reduce attack time
1004 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1006 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1007 float percent60
= 3 * percent20
;
1008 if(offtime
> percent20
&& offtime
<= percent60
)
1010 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1012 else if(offtime
> percent60
)
1014 offtime
-= 2 * percent20
;
1015 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1020 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1021 float percent60
= 3 * percent20
;
1022 if(basetime
> percent20
&& basetime
<= percent60
)
1024 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1026 else if(basetime
> percent60
)
1028 basetime
-= 2 * percent20
;
1029 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1034 // Update victim defense ?
1035 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1036 ((Player
*)pVictim
)->UpdateDefense();
1039 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1040 pVictim
->ModifyAuraState(AURA_STATE_PARRY
, true);
1043 case MELEE_HIT_DODGE
:
1045 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1046 ((Player
*)pVictim
)->UpdateDefense();
1048 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1050 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1051 victimState
= VICTIMSTATE_DODGE
;
1054 case MELEE_HIT_BLOCK
:
1056 uint32 blocked_amount
;
1057 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1058 if (blocked_amount
>= *damage
)
1060 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1061 victimState
= VICTIMSTATE_BLOCKS
;
1062 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1067 // To Help Calculate Rage
1068 cleanDamage
->damage
+= blocked_amount
;
1069 *damage
= *damage
- blocked_amount
;
1074 case MELEE_HIT_MISS
:
1075 case MELEE_HIT_GLANCING
:
1076 case MELEE_HIT_CRUSHING
:
1077 case MELEE_HIT_NORMAL
:
1081 // Update attack state
1082 SendAttackStateUpdate(victimState
? hitInfo
|victimState
: hitInfo
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
1084 // do all damage=0 cases here
1086 CastMeleeProcDamageAndSpell(pVictim
,0,BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1091 case SPELL_SCHOOL_HOLY
:
1092 case SPELL_SCHOOL_FIRE
:
1093 case SPELL_SCHOOL_NATURE
:
1094 case SPELL_SCHOOL_FROST
:
1095 case SPELL_SCHOOL_SHADOW
:
1096 case SPELL_SCHOOL_ARCANE
:
1098 //Spell miss (sends resist message)
1099 if(SpellMissChanceCalc(pVictim
) > urand(0,10000))
1101 cleanDamage
->damage
= 0;
1103 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, spellInfo
,isTriggeredSpell
);
1104 SendAttackStateUpdate(HITINFO_RESIST
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
1108 // Calculate damage bonus
1109 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1111 // Calculate critical bonus
1112 *crit
= SpellCriticalBonus(spellInfo
, (int32
*)damage
, pVictim
);
1113 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1115 // spell proc all magic damage==0 case in this function
1119 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1120 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1122 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, spellInfo
, isTriggeredSpell
);
1128 // TODO this in only generic way, check for exceptions
1129 DEBUG_LOG("DealDamageBySchool (AFTER) SCHOOL %u >> DMG:%u", spellInfo
->School
, *damage
);
1132 void Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1134 if(!this || !pVictim
)
1136 if(!this->isAlive() || !pVictim
->isAlive())
1139 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1143 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1147 DealDamageBySchool(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1149 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealDamageBySchool)
1152 // Calculate absorb & resists
1156 CalcAbsorbResist(pVictim
,SpellSchools(spellInfo
->School
), damage
, &absorb
, &resist
);
1158 // Only send absorbed message if we actually absorbed some damage
1161 // Handle absorb &Â resists
1162 if(damage
<= absorb
+ resist
&& absorb
)
1164 SendAttackStateUpdate(HITINFO_ABSORB
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
),damage
, absorb
,resist
,1,0);
1167 else if(damage
<= resist
) // If we didn't fully absorb check if we fully resisted
1169 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, spellInfo
,isTriggeredSpell
);
1170 SendAttackStateUpdate(HITINFO_RESIST
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
), damage
, absorb
,resist
,1,0);
1176 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1177 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1178 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, SpellSchools(spellInfo
->School
), absorb
, resist
, false, 0, crit
);
1181 DealDamage(pVictim
, (damage
-absorb
-resist
), &cleanDamage
, SPELL_DIRECT_DAMAGE
, SpellSchools(spellInfo
->School
), spellInfo
, 0, true);
1184 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1185 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1189 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1190 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1193 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, (damage
-absorb
-resist
), spellInfo
, isTriggeredSpell
);
1197 // all spell proc for 0 normal and magic damage called in DealDamageBySchool
1200 if(cleanDamage
.damage
)
1201 // Rage from physical damage received.
1202 if(spellInfo
->School
==SPELL_SCHOOL_NORMAL
&& pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1203 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1207 void Unit::PeriodicAuraLog(Unit
*pVictim
, SpellEntry
const *spellProto
, Modifier
*mod
, uint8 effect_idx
)
1209 uint32 procFlag
= 0;
1210 if(!this || !pVictim
|| !isAlive() || !pVictim
->isAlive())
1216 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1217 uint32 pdamage
= mod
->m_amount
;
1219 if(mod
->m_auraname
!= SPELL_AURA_PERIODIC_HEAL
&& mod
->m_auraname
!= SPELL_AURA_OBS_MOD_HEALTH
)
1221 //Calculate armor mitigation if it is a physical spell
1222 if (spellProto
->School
== 0)
1224 uint32 pdamageReductedArmor
= CalcArmorReducedDamage(pVictim
, pdamage
);
1225 cleanDamage
.damage
+= pdamage
- pdamageReductedArmor
;
1226 pdamage
= pdamageReductedArmor
;
1229 CalcAbsorbResist(pVictim
, SpellSchools(spellProto
->School
), pdamage
, &absorb
, &resist
);
1232 sLog
.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
1233 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), pdamage
, spellProto
->Id
,absorb
);
1235 switch(mod
->m_auraname
)
1237 case SPELL_AURA_PERIODIC_DAMAGE
:
1238 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
1240 pdamage
= SpellDamageBonus(pVictim
,spellProto
,pdamage
,DOT
);
1242 if(mod
->m_auraname
== SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
1243 pdamage
= GetHealth()*(100+mod
->m_amount
)/100;
1245 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1246 data
.append(pVictim
->GetPackGUID());
1247 data
.append(GetPackGUID());
1248 data
<< uint32(spellProto
->Id
);
1250 data
<< uint32(mod
->m_auraname
);
1251 data
<< (uint32
)pdamage
;
1252 data
<< (uint32
)spellProto
->School
;
1253 data
<< (uint32
)absorb
;
1254 data
<< (uint32
)resist
;
1255 SendMessageToSet(&data
,true);
1257 DealDamage(pVictim
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), &cleanDamage
, DOT
, SpellSchools(spellProto
->School
), spellProto
, procFlag
, true);
1258 ProcDamageAndSpell(pVictim
, PROC_FLAG_HIT_SPELL
, PROC_FLAG_TAKE_DAMAGE
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), spellProto
);
1261 case SPELL_AURA_PERIODIC_HEAL
:
1262 case SPELL_AURA_OBS_MOD_HEALTH
:
1264 pdamage
= SpellHealingBonus(spellProto
, pdamage
, DOT
, pVictim
);
1266 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1267 data
.append(pVictim
->GetPackGUID());
1268 data
.append(GetPackGUID());
1269 data
<< uint32(spellProto
->Id
);
1271 data
<< uint32(mod
->m_auraname
);
1272 data
<< (uint32
)pdamage
;
1273 SendMessageToSet(&data
,true);
1275 int32 gain
= pVictim
->ModifyHealth(pdamage
);
1276 pVictim
->getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1278 // heal for caster damage
1279 if(pVictim
!=this && spellProto
->SpellVisual
==163)
1281 uint32 dmg
= spellProto
->manaPerSecond
;
1282 if(GetHealth() <= dmg
&& GetTypeId()==TYPEID_PLAYER
)
1284 RemoveAurasDueToSpell(spellProto
->Id
);
1286 // finish current generic/channeling spells, don't affect autorepeat
1287 if(m_currentSpells
[CURRENT_GENERIC_SPELL
])
1289 m_currentSpells
[CURRENT_GENERIC_SPELL
]->finish();
1291 if(m_currentSpells
[CURRENT_CHANNELED_SPELL
])
1293 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SendChannelUpdate(0);
1294 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->finish();
1299 SendSpellNonMeleeDamageLog(this, spellProto
->Id
, gain
, SpellSchools(spellProto
->School
), 0, 0, false, 0, false);
1300 DealDamage(this, gain
, &cleanDamage
, NODAMAGE
, SpellSchools(spellProto
->School
), spellProto
, PROC_FLAG_HEAL
, true);
1304 if(mod
->m_auraname
== SPELL_AURA_PERIODIC_HEAL
&& pVictim
!= this)
1305 ProcDamageAndSpell(pVictim
, PROC_FLAG_HEAL
, PROC_FLAG_HEALED
, pdamage
, spellProto
);
1308 case SPELL_AURA_PERIODIC_LEECH
:
1310 float multiplier
= spellProto
->EffectMultipleValue
[effect_idx
] > 0 ? spellProto
->EffectMultipleValue
[effect_idx
] : 1;
1311 uint32 pdamage
= mod
->m_amount
;
1313 pdamage
= SpellDamageBonus(pVictim
,spellProto
,pdamage
,DOT
);
1315 if(pVictim
->GetHealth() < pdamage
)
1316 pdamage
= uint32(pVictim
->GetHealth());
1318 SendSpellNonMeleeDamageLog(pVictim
, spellProto
->Id
, pdamage
, SpellSchools(spellProto
->School
), absorb
, resist
, false, 0);
1319 DealDamage(pVictim
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), &cleanDamage
, DOT
, SpellSchools(spellProto
->School
), spellProto
, procFlag
, false);
1320 ProcDamageAndSpell(pVictim
, PROC_FLAG_HIT_SPELL
, PROC_FLAG_TAKE_DAMAGE
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), spellProto
);
1321 if (!pVictim
->isAlive() && IsNonMeleeSpellCasted(false))
1323 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
1325 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
== spellProto
->Id
)
1326 m_currentSpells
[i
]->cancel();
1330 int32 gain
= ModifyHealth(int32(pdamage
* multiplier
));
1331 getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1333 if(GetTypeId() == TYPEID_PLAYER
)
1334 SendHealSpellOnPlayer(this, spellProto
->Id
, uint32(pdamage
* multiplier
));
1337 case SPELL_AURA_PERIODIC_MANA_LEECH
:
1339 if(mod
->m_miscvalue
< 0 || mod
->m_miscvalue
> 4)
1342 Powers power
= Powers(mod
->m_miscvalue
);
1344 int32 drain_amount
= pVictim
->GetPower(power
) > pdamage
? pdamage
: pVictim
->GetPower(power
);
1346 pVictim
->ModifyPower(power
, -drain_amount
);
1348 float gain_multiplier
= GetMaxPower(power
) > 0 ? spellProto
->EffectMultipleValue
[effect_idx
] : 0;
1350 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1351 data
.append(pVictim
->GetPackGUID());
1352 data
.append(GetPackGUID());
1353 data
<< uint32(spellProto
->Id
);
1355 data
<< uint32(mod
->m_auraname
);
1356 data
<< (uint32
)power
; // power type
1357 data
<< (uint32
)drain_amount
;
1358 data
<< (float)gain_multiplier
;
1359 SendMessageToSet(&data
,true);
1361 int32 gain_amount
= int32(drain_amount
*gain_multiplier
);
1365 int32 gain
= ModifyPower(power
,gain_amount
);
1366 pVictim
->AddThreat(this, float(gain
) * 0.5f
, SpellSchools(spellProto
->School
), spellProto
);
1370 case SPELL_AURA_PERIODIC_ENERGIZE
:
1372 if(mod
->m_miscvalue
< 0 || mod
->m_miscvalue
> 4)
1375 Powers power
= Powers(mod
->m_miscvalue
);
1377 if(pVictim
->GetMaxPower(power
) == 0)
1380 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1381 data
.append(pVictim
->GetPackGUID());
1382 data
.append(GetPackGUID());
1383 data
<< uint32(spellProto
->Id
);
1385 data
<< uint32(mod
->m_auraname
);
1386 data
<< (uint32
)power
; // power type
1387 data
<< (uint32
)mod
->m_amount
;
1388 SendMessageToSet(&data
,true);
1390 int32 gain
= pVictim
->ModifyPower(power
,mod
->m_amount
);
1391 pVictim
->getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1394 case SPELL_AURA_OBS_MOD_MANA
:
1396 if(GetMaxPower(POWER_MANA
) == 0)
1399 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1400 data
.append(pVictim
->GetPackGUID());
1401 data
.append(GetPackGUID());
1402 data
<< uint32(spellProto
->Id
);
1404 data
<< uint32(mod
->m_auraname
);
1405 data
<< (uint32
)mod
->m_amount
;
1406 data
<< (uint32
)0; // ?
1407 SendMessageToSet(&data
,true);
1409 int32 gain
= ModifyPower(POWER_MANA
, mod
->m_amount
);
1410 getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1416 void Unit::HandleEmoteCommand(uint32 anim_id
)
1418 WorldPacket
data( SMSG_EMOTE
, 12 );
1419 data
<< anim_id
<< GetGUID();
1420 WPAssert(data
.size() == 12);
1422 SendMessageToSet(&data
, true);
1425 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1427 uint32 newdamage
= 0;
1428 float armor
= pVictim
->GetArmor();
1430 float tmpvalue
= 0.0;
1431 if(getLevel() <= 59) //Level 1-59
1432 tmpvalue
= armor
/ (armor
+ 400.0 + 85.0 * getLevel());
1433 else if(getLevel() < 70) //Level 60-69
1434 tmpvalue
= armor
/ (armor
- 22167.5 + 467.5 * getLevel());
1436 tmpvalue
= armor
/ (armor
+ 10557.5);
1442 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1444 return (newdamage
> 1) ? newdamage
: 1;
1447 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchools school
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1449 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1452 // Magic damage, check for resists
1453 if (school
!= SPELL_SCHOOL_NORMAL
)
1455 int32 tmpvalue2
= pVictim
->GetResistance(school
);
1456 AuraList
const& mModTargetRes
= GetAurasByType(SPELL_AURA_MOD_TARGET_RESISTANCE
);
1457 for(AuraList::const_iterator i
= mModTargetRes
.begin(); i
!= mModTargetRes
.end(); ++i
)
1458 if ((*i
)->GetModifier()->m_miscvalue
& int32(1 << school
))
1459 tmpvalue2
+= (*i
)->GetModifier()->m_amount
;
1460 if (tmpvalue2
< 0) tmpvalue2
= 0;
1461 *resist
+= uint32(damage
*tmpvalue2
*0.0025*pVictim
->getLevel()/getLevel());
1462 if(*resist
> damage
)
1468 int32 RemainingDamage
= damage
- *resist
;
1469 int32 currentAbsorb
, manaReduction
, maxAbsorb
;
1470 float manaMultiplier
;
1472 if (school
== SPELL_SCHOOL_NORMAL
)
1474 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1475 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
>= 0; i
= next
)
1478 if (RemainingDamage
- (*i
)->m_absorbDmg
>= 0)
1479 currentAbsorb
= (*i
)->m_absorbDmg
;
1481 currentAbsorb
= RemainingDamage
;
1483 manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1484 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1485 if (currentAbsorb
> maxAbsorb
)
1486 currentAbsorb
= maxAbsorb
;
1488 (*i
)->m_absorbDmg
-= currentAbsorb
;
1489 if((*i
)->m_absorbDmg
<= 0)
1491 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1492 next
= vManaShield
.begin();
1495 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1496 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1498 RemainingDamage
-= currentAbsorb
;
1502 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1503 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
>= 0; i
= next
)
1506 if ((*i
)->GetModifier()->m_miscvalue
& int32(1<<school
))
1508 if (RemainingDamage
- (*i
)->m_absorbDmg
>= 0)
1510 currentAbsorb
= (*i
)->m_absorbDmg
;
1511 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1512 next
= vSchoolAbsorb
.begin();
1516 currentAbsorb
= RemainingDamage
;
1517 (*i
)->m_absorbDmg
-= RemainingDamage
;
1520 RemainingDamage
-= currentAbsorb
;
1524 *absorb
= damage
- RemainingDamage
- *resist
;
1527 void Unit::DoAttackDamage (Unit
*pVictim
, uint32
*damage
, CleanDamage
*cleanDamage
, uint32
*blocked_amount
, SpellSchools damageType
, uint32
*hitInfo
, uint32
*victimState
, uint32
*absorbDamage
, uint32
*resistDamage
, WeaponAttackType attType
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
1529 pVictim
->ModifyAuraState(AURA_STATE_PARRY
, false);
1530 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, false);
1531 ModifyAuraState(AURA_STATE_CRIT
, false);
1533 MeleeHitOutcome outcome
;
1535 // If is casted Melee spell, calculate like physical
1537 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1539 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1541 if (outcome
== MELEE_HIT_MISS
)
1543 *hitInfo
|= HITINFO_MISS
;
1545 cleanDamage
->damage
= 0;
1546 if(GetTypeId()== TYPEID_PLAYER
)
1547 ((Player
*)this)->UpdateWeaponSkill(attType
);
1551 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1552 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1553 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1555 // -probability is between 0% and 40%
1557 float Probability
= 20;
1559 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1560 if( pVictim
->getLevel() < 30 )
1561 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1563 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue();
1564 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill();
1566 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1568 if(Probability
> 40)
1571 if(roll_chance_f(Probability
))
1572 CastSpell(pVictim
, 1604, true);
1575 *damage
+= CalculateDamage (attType
);
1577 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1578 if (damageType
== SPELL_SCHOOL_NORMAL
)
1580 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1581 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1582 *damage
= damageAfterArmor
;
1584 // Instant Attacks (Spellmods)
1585 // TODO: AP bonus related to mainhand weapon
1587 if(GetTypeId()== TYPEID_PLAYER
)
1588 ((Player
*)this)->ApplySpellMod(spellCasted
->Id
, SPELLMOD_DAMAGE
, *damage
);
1590 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1591 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1593 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1594 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1598 case MELEE_HIT_CRIT
:
1601 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| 0x8;
1605 crit_bonus
= *damage
;
1607 // Apply crit_damage bonus for melee spells
1608 if (GetTypeId() == TYPEID_PLAYER
&& spellCasted
)
1610 ((Player
*)this)->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1613 *damage
+= crit_bonus
;
1615 // Resilience - reduce crit damage by 2x%
1616 uint32 resilienceReduction
;
1617 resilienceReduction
= uint32(pVictim
->m_modResilience
* 2/100 * (*damage
));
1618 *damage
-= resilienceReduction
;
1619 cleanDamage
->damage
+= resilienceReduction
;
1621 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1622 ((Player
*)this)->UpdateWeaponSkill(attType
);
1624 ModifyAuraState(AURA_STATE_CRIT
, true);
1626 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1629 case MELEE_HIT_PARRY
:
1630 if(attType
== RANGED_ATTACK
) //range attack - no parry
1633 cleanDamage
->damage
+= *damage
;
1635 *victimState
= VICTIMSTATE_PARRY
;
1637 // instant (maybe with small delay) counter attack
1639 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1640 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1642 // after parry nearest next attack time will reduced at %40 from full attack time.
1643 // The delay cannot be reduced to less than 20% of your weapon’s base swing delay.
1644 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1646 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1647 float percent60
= 3*percent20
;
1648 // set to 20% if in range 20%...20+40% of full time
1649 if(offtime
> percent20
&& offtime
<= percent60
)
1651 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1653 // decrease at %40 from full time
1654 else if(offtime
> percent60
)
1656 offtime
-= 2*percent20
;
1657 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1663 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1664 float percent60
= 3*percent20
;
1665 // set to 20% if in range 20%...20+40% of full time
1666 if(basetime
> percent20
&& basetime
<= percent60
)
1668 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1670 // decrease at %40 from full time
1671 else if(basetime
> percent60
)
1673 basetime
-= 2*percent20
;
1674 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1680 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1681 ((Player
*)pVictim
)->UpdateDefense();
1683 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1684 pVictim
->ModifyAuraState(AURA_STATE_PARRY
,true);
1685 if (pVictim
->getClass() != CLASS_HUNTER
) // Mongoose Bite
1686 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1688 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1691 case MELEE_HIT_DODGE
:
1692 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1694 cleanDamage
->damage
+= *damage
;
1696 *victimState
= VICTIMSTATE_DODGE
;
1698 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1699 ((Player
*)pVictim
)->UpdateDefense();
1701 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1703 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1704 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1706 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1709 case MELEE_HIT_BLOCK
:
1710 *blocked_amount
= uint32(pVictim
->GetShieldBlockValue() + (pVictim
->GetStat(STAT_STRENGTH
) / 20.0f
) -1);
1712 if (pVictim
->GetUnitBlockChance())
1713 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1715 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1717 //Only set VICTIMSTATE_BLOCK on a full block
1718 if (*blocked_amount
>= *damage
)
1720 *victimState
= VICTIMSTATE_BLOCKS
;
1721 *blocked_amount
= *damage
;
1724 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1725 ((Player
*)pVictim
)->UpdateDefense();
1726 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1729 case MELEE_HIT_GLANCING
:
1731 float reducePercent
= 1.0f
; //damage factor
1733 // calculate base values and mods
1734 float baseLowEnd
= 1.3;
1735 float baseHighEnd
= 1.2;
1736 switch(getClass()) // lowering base values for casters
1748 float maxLowEnd
= 0.6;
1749 switch(getClass()) // upper for melee classes
1753 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
1757 int32 diff
= pVictim
->GetDefenseSkillValue() - GetWeaponSkillValue(attType
);
1758 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
1759 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
1761 // apply max/min bounds
1762 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
1764 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
1767 if ( highEnd
< 0.2f
) //high end limits
1769 if ( highEnd
> 0.99f
)
1772 if(lowEnd
> highEnd
) // prevent negative range size
1775 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
1777 *damage
= uint32(reducePercent
* *damage
);
1778 cleanDamage
->damage
+= *damage
;
1779 *hitInfo
|= HITINFO_GLANCING
;
1782 case MELEE_HIT_CRUSHING
:
1784 // 150% normal damage
1785 *damage
+= (*damage
/ 2);
1786 cleanDamage
->damage
= *damage
;
1787 *hitInfo
|= HITINFO_CRUSHING
;
1788 // TODO: victimState, victim animation?
1795 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
1796 if(*victimState
!= VICTIMSTATE_BLOCKS
)
1798 MeleeDamageBonus(pVictim
, damage
,attType
);
1799 CalcAbsorbResist(pVictim
, damageType
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
1802 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
1803 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
1804 cleanDamage
+= *blocked_amount
;
1806 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
1808 //*hitInfo = 0x00010020;
1809 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1811 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1815 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), attType
, outcome
, spellCasted
, isTriggeredSpell
);
1817 // victim's damage shield
1818 // yet another hack to fix crashes related to the aura getting removed during iteration
1819 std::set
<Aura
*> alreadyDone
;
1820 uint32 removedAuras
= pVictim
->m_removedAuras
;
1821 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
1822 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
1825 if (alreadyDone
.find(*i
) == alreadyDone
.end())
1827 alreadyDone
.insert(*i
);
1828 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
1829 if (pVictim
->m_removedAuras
> removedAuras
)
1831 removedAuras
= pVictim
->m_removedAuras
;
1832 next
= vDamageShields
.begin();
1837 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& *damage
)
1839 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
1841 // skip channeled spell (processed differently below)
1842 if (i
== CURRENT_CHANNELED_SPELL
)
1845 if(pVictim
->m_currentSpells
[i
])
1847 sLog
.outDetail("Spell Delayed!%d",(int32
)(0.25f
* pVictim
->m_currentSpells
[i
]->casttime
));
1848 pVictim
->m_currentSpells
[i
]->Delayed((int32
)(0.25f
* pVictim
->m_currentSpells
[i
]->casttime
));
1852 // process channeled spell separately
1853 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
1855 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_CASTING
)
1857 uint32 channelInterruptFlags
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->ChannelInterruptFlags
;
1858 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
1860 sLog
.outDetail("Spell Delayed!%d",(int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
1861 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->DelayedChannel((int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
1864 else if( !(channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
1867 sLog
.outDetail("Spell Canceled!");
1868 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
1870 else if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_DELAYED
)
1872 // break channeled spell in delayed state on damage
1873 sLog
.outDetail("Spell Canceled!");
1874 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
1880 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool isTriggered
)
1882 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNDED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
1885 if (!pVictim
->isAlive())
1890 if(IsNonMeleeSpellCasted(false))
1893 // melee attack spell casted at main hand attack only
1894 if (m_currentSpells
[CURRENT_MELEE_SPELL
] && attType
== BASE_ATTACK
)
1896 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
1902 if (attType
== BASE_ATTACK
)
1903 hitInfo
= HITINFO_NORMALSWING2
;
1904 else if (attType
== OFF_ATTACK
)
1905 hitInfo
= HITINFO_LEFTSWING
;
1909 uint32 victimState
= VICTIMSTATE_NORMAL
;
1912 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1913 uint32 blocked_dmg
= 0;
1914 uint32 absorbed_dmg
= 0;
1915 uint32 resisted_dmg
= 0;
1917 if( pVictim
->IsImmunedToPhysicalDamage() )
1919 SendAttackStateUpdate (HITINFO_MISS
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
1923 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, SPELL_SCHOOL_NORMAL
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
1925 cleanDamage
.damage
+= blocked_dmg
;
1927 if (hitInfo
& HITINFO_MISS
)
1929 SendAttackStateUpdate (hitInfo
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
1933 SendAttackStateUpdate (hitInfo
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
1935 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
1936 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
1940 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, SPELL_SCHOOL_NORMAL
, NULL
, 0, true);
1942 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
1944 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
1945 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
);
1949 if (GetTypeId() == TYPEID_PLAYER
)
1950 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1951 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
1953 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1954 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
1957 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
1959 // Miss chance based on melee
1960 int32 miss_chance
= (int32
)(MeleeMissChanceCalc(pVictim
));
1962 // Critical hit chance
1963 float crit_chance
= GetUnitCriticalChance(attType
);
1965 // Only players can have Talent&Spell bonuses
1966 if (GetTypeId() == TYPEID_PLAYER
)
1969 AuraList
const& mSpellCritSchool
= GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
);
1970 for(AuraList::const_iterator i
= mSpellCritSchool
.begin(); i
!= mSpellCritSchool
.end(); ++i
)
1971 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellInfo
->School
)) != 0)
1972 crit_chance
+= (*i
)->GetModifier()->m_amount
;
1975 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
1976 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
1977 crit_chance
+= (*i
)->GetModifier()->m_amount
;
1980 ((Player
*)this)->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
1983 DEBUG_LOG("PHYSICAL OUTCOME: hit %u crit %f miss %u",m_modHitChance
,crit_chance
,miss_chance
);
1985 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
* 100 ), miss_chance
, m_modHitChance
);
1988 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
) const
1990 // This is only wrapper
1992 // Miss chance based on melee
1993 int32 miss_chance
= (int32
)(MeleeMissChanceCalc(pVictim
));
1995 // Critical hit chance
1996 float crit_chance
= GetUnitCriticalChance(attType
);
1999 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
2000 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
2001 crit_chance
+= (*i
)->GetModifier()->m_amount
;
2003 // Useful if want to specify crit & miss chances for melee, else it could be removed
2004 DEBUG_LOG("MELEE OUTCOME: hit %u crit %u miss %u", m_modHitChance
,crit_chance
,miss_chance
);
2005 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
* 100 ), miss_chance
, m_modHitChance
);
2008 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, int32 crit_chance
, int32 miss_chance
, int32 hit_chance
) const
2010 int32 skillDiff
= GetWeaponSkillValue(attType
) - pVictim
->GetDefenseSkillValue();
2011 // bonus from skills is 0.04%
2012 int32 skillBonus
= skillDiff
* 4;
2013 int32 skillBonus2
= 4 * ( GetWeaponSkillValue(attType
) - pVictim
->GetPureDefenseSkillValue() );
2014 int32 sum
= 0, tmp
= 0;
2015 int32 roll
= urand (0, 10000);
2017 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2018 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
2019 roll
, hit_chance
, (uint32
)(pVictim
->GetUnitDodgeChance()*100), (uint32
)(pVictim
->GetUnitParryChance()*100),
2020 (uint32
)(pVictim
->GetUnitBlockChance()*100), crit_chance
);
2022 // dual wield has 24% base chance to miss instead of 5%, also
2023 // base miss rate is 5% and can't get higher than 60%
2025 // Inherit if passed
2026 tmp
= miss_chance
- skillBonus
;
2031 if (tmp
> 0 && roll
< (sum
+= tmp
))
2033 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2034 return MELEE_HIT_MISS
;
2037 // always crit against a sitting target (except 0 crit chance)
2038 if( (pVictim
->GetTypeId() == TYPEID_PLAYER
) && crit_chance
> 0 &&
2039 (((Player
*)pVictim
)->getStandState() & (PLAYER_STATE_SLEEP
| PLAYER_STATE_SIT
2040 | PLAYER_STATE_SIT_CHAIR
2041 | PLAYER_STATE_SIT_LOW_CHAIR
2042 | PLAYER_STATE_SIT_MEDIUM_CHAIR
2043 | PLAYER_STATE_SIT_HIGH_CHAIR
)))
2045 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2046 return MELEE_HIT_CRIT
;
2049 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2050 tmp
= (int32
)(pVictim
->GetUnitDodgeChance()*100) - skillBonus2
;
2051 if (tmp
> 0 && roll
< (sum
+= tmp
))
2053 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2054 return MELEE_HIT_DODGE
;
2059 // check if attack comes from behind
2060 if (!pVictim
->HasInArc(M_PI
,this))
2062 // ASSUME +10% crit from behind
2063 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2068 // cannot parry or block attacks from behind, but can from forward
2069 tmp
= (int32
)(pVictim
->GetUnitParryChance()*100);
2070 if ( (tmp
> 0) // check if unit _can_ parry
2071 && ((tmp
-= skillBonus2
) > 0)
2072 && (roll
< (sum
+= tmp
)))
2074 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2075 return MELEE_HIT_PARRY
;
2078 tmp
= (int32
)(pVictim
->GetUnitBlockChance()*100);
2079 if ( (tmp
> 0) // check if unit _can_ block
2080 && ((tmp
-= skillBonus2
) > 0)
2081 && (roll
< (sum
+= tmp
)))
2083 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2084 return MELEE_HIT_BLOCK
;
2088 // Resilience - reduce crit chance by x%
2089 modCrit
-= int32(pVictim
->m_modResilience
*100);
2092 tmp
= crit_chance
+ skillBonus
+ modCrit
;
2094 if (tmp
> 0 && roll
< (sum
+= tmp
))
2096 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2097 return MELEE_HIT_CRIT
;
2100 // Max 40% chance to score a glancing blow against mobs that are higher level
2101 if( GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& getLevel() < pVictim
->getLevel() )
2103 // cap possible value (with bonuses > max skill)
2104 int32 skill
= GetWeaponSkillValue(attType
);
2105 int32 maxskill
= GetMaxSkillValueForLevel();
2106 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2108 tmp
= (10 + (pVictim
->GetDefenseSkillValue() - skill
)) * 100;
2109 tmp
= tmp
> 4000 ? 4000 : tmp
;
2110 if (roll
< (sum
+= tmp
))
2112 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2113 return MELEE_HIT_GLANCING
;
2117 // mobs can score crushing blows if they're 3 or more levels above victim
2118 // or when their weapon skill is 15 or more above victim's defense skill
2119 tmp
= pVictim
->GetDefenseSkillValue();
2120 int32 tmpmax
= pVictim
->GetMaxSkillValueForLevel();
2121 // having defense above your maximum (from items, talents etc.) has no effect
2122 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2123 // tmp = mob's level * 5 - player's current defense skill
2124 tmp
= GetMaxSkillValueForLevel() - tmp
;
2125 if (GetTypeId() != TYPEID_PLAYER
&& (tmp
>= 15))
2127 // add 2% chance per lacking skill point, min. is 15%
2128 tmp
= tmp
* 200 - 1500;
2129 if (roll
< (sum
+= tmp
))
2131 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2132 return MELEE_HIT_CRUSHING
;
2136 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2137 return MELEE_HIT_NORMAL
;
2140 uint32
Unit::CalculateDamage (WeaponAttackType attType
)
2142 float min_damage
, max_damage
;
2147 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2148 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2151 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2152 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2155 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2156 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2160 if (min_damage
> max_damage
)
2162 std::swap(min_damage
,max_damage
);
2165 if(max_damage
== 0.0)
2168 return rand32((uint32
)min_damage
, (uint32
)max_damage
);
2171 void Unit::SendAttackStart(Unit
* pVictim
)
2173 if(GetTypeId()!=TYPEID_PLAYER
|| !pVictim
)
2176 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2178 data
<< pVictim
->GetGUID();
2180 ((Player
*)this)->SendMessageToSet(&data
, true);
2181 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2184 void Unit::SendAttackStop(Unit
* victim
)
2189 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2190 data
.append(GetPackGUID());
2191 data
.append(victim
->GetPackGUID()); // can be 0x00...
2192 data
<< uint32(0); // can be 0x1
2193 SendMessageToSet(&data
, true);
2194 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2196 /*if(victim->GetTypeId() == TYPEID_UNIT)
2197 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2200 uint32
Unit::SpellMissChanceCalc(Unit
*pVictim
) const
2205 // PvP : PvE spell misschances per leveldif > 2
2206 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 700 : 1100;
2208 int32 leveldif
= pVictim
->getLevel() - getLevel();
2212 int32 misschance
= 400 - m_modSpellHitChance
*100;
2214 misschance
+= leveldif
* 100;
2216 misschance
+= (leveldif
- 2) * chance
;
2218 return misschance
< 100 ? 100 : misschance
;
2221 int32
Unit::MeleeMissChanceCalc(const Unit
*pVictim
) const
2226 // Base misschance 5%
2227 int32 misschance
= 500;
2229 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2230 if (haveOffhandWeapon())
2232 bool isNormal
= false;
2233 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2235 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->School
== SPELL_SCHOOL_NORMAL
)
2241 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2251 // PvP : PvE melee misschances per leveldif > 2
2252 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 500 : 700;
2254 int32 leveldif
= pVictim
->getLevel() - getLevel();
2259 misschance
+= leveldif
* 100 - m_modHitChance
*100;
2261 misschance
+= (leveldif
- 2) * chance
- m_modHitChance
*100;
2263 return misschance
> 6000 ? 6000 : misschance
;
2266 uint16
Unit::GetDefenseSkillValue() const
2268 if(GetTypeId() == TYPEID_PLAYER
)
2269 return ((Player
*)this)->GetSkillValue (SKILL_DEFENSE
);
2271 return GetUnitMeleeSkill();
2274 uint16
Unit::GetPureDefenseSkillValue() const
2276 if(GetTypeId() == TYPEID_PLAYER
)
2277 return ((Player
*)this)->GetPureSkillValue(SKILL_DEFENSE
);
2279 return GetUnitMeleeSkill();
2282 float Unit::GetUnitDodgeChance() const
2284 if(hasUnitState(UNIT_STAT_STUNDED
))
2286 return GetTypeId() == TYPEID_PLAYER
? GetFloatValue(PLAYER_DODGE_PERCENTAGE
) : 5;
2289 float Unit::GetUnitParryChance() const
2292 if(GetTypeId() == TYPEID_PLAYER
)
2294 Player
const* player
= (Player
const*)this;
2295 if(player
->CanParry() && player
->IsUseEquipedWeapon() )
2297 Item
*tmpitem
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
2298 if(!tmpitem
|| tmpitem
->IsBroken())
2299 tmpitem
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
2301 if(tmpitem
&& !tmpitem
->IsBroken() && (
2302 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPON
||
2303 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPONOFFHAND
||
2304 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPONMAINHAND
||
2305 tmpitem
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
))
2306 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
2309 else if(GetTypeId() == TYPEID_UNIT
)
2311 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
2318 float Unit::GetUnitBlockChance() const
2321 if(GetTypeId() == TYPEID_PLAYER
)
2323 Item
*tmpitem
= ((Player
const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
2324 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
2325 chance
= GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
2333 uint16
Unit::GetWeaponSkillValue (WeaponAttackType attType
) const
2335 if(GetTypeId() == TYPEID_PLAYER
)
2340 case BASE_ATTACK
: slot
= EQUIPMENT_SLOT_MAINHAND
; break;
2341 case OFF_ATTACK
: slot
= EQUIPMENT_SLOT_OFFHAND
; break;
2342 case RANGED_ATTACK
: slot
= EQUIPMENT_SLOT_RANGED
; break;
2346 Item
*item
= ((Player
*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0
, slot
);
2348 if(slot
!= EQUIPMENT_SLOT_MAINHAND
&& (!item
|| item
->IsBroken() ||
2349 item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((Player
*)this)->IsUseEquipedWeapon() ))
2353 uint32 skill
= item
&& !item
->IsBroken() && ((Player
*)this)->IsUseEquipedWeapon()
2354 ? item
->GetSkill() : SKILL_UNARMED
;
2355 return ((Player
*)this)->GetSkillValue (skill
);
2358 return GetUnitMeleeSkill();
2361 uint16
Unit::GetPureWeaponSkillValue (WeaponAttackType attType
) const
2363 if(GetTypeId() == TYPEID_PLAYER
)
2368 case BASE_ATTACK
: slot
= EQUIPMENT_SLOT_MAINHAND
; break;
2369 case OFF_ATTACK
: slot
= EQUIPMENT_SLOT_OFFHAND
; break;
2370 case RANGED_ATTACK
: slot
= EQUIPMENT_SLOT_RANGED
; break;
2374 Item
*item
= ((Player
*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0
, slot
);
2376 if(slot
!= EQUIPMENT_SLOT_MAINHAND
&& (!item
|| item
->IsBroken() ||
2377 item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((Player
*)this)->IsUseEquipedWeapon() ))
2381 uint32 skill
= item
&& !item
->IsBroken() && ((Player
*)this)->IsUseEquipedWeapon()
2382 ? item
->GetSkill() : SKILL_UNARMED
;
2383 return ((Player
*)this)->GetPureSkillValue (skill
);
2386 return GetUnitMeleeSkill();
2389 void Unit::_UpdateSpells( uint32 time
)
2391 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
2392 _UpdateAutoRepeatSpell( time
);
2394 // remove finished spells from current pointers
2395 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
2397 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
2399 m_currentSpells
[i
]->SetDeletable(true); // spell may be safely deleted now
2400 m_currentSpells
[i
] = NULL
; // remove pointer
2404 // TODO: Find a better way to prevent crash when multiple auras are removed.
2406 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
2408 (*i
).second
->SetUpdated(false);
2410 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
2416 // prevent double update
2417 if ((*i
).second
->IsUpdated())
2419 (*i
).second
->SetUpdated(true);
2420 (*i
).second
->Update( time
);
2421 // several auras can be deleted due to update
2424 if (m_Auras
.empty()) break;
2425 next
= m_Auras
.begin();
2431 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
2435 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
2450 if(!m_gameObj
.empty())
2452 std::list
<GameObject
*>::iterator ite1
, dnext1
;
2453 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
2456 //(*i)->Update( difftime );
2457 if( !(*ite1
)->isSpawned() )
2459 (*ite1
)->SetOwnerGUID(0);
2460 (*ite1
)->SetRespawnTime(0);
2462 dnext1
= m_gameObj
.erase(ite1
);
2470 void Unit::_UpdateAutoRepeatSpell( uint32 time
)
2472 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_FINISHED
)
2475 if( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->AttributesEx2
== 0x000020 && GetTypeId() == TYPEID_PLAYER
)
2477 // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
2478 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2481 resetAttackTimer( RANGED_ATTACK
);
2486 if (m_AutoRepeatFirstCast
)
2488 // first cast only with recovery time (not less)
2489 if (getAttackTimer( RANGED_ATTACK
) < m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
)
2490 setAttackTimer( RANGED_ATTACK
, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
);
2491 m_AutoRepeatFirstCast
= false;
2495 // second or further casts
2496 resetAttackTimer( RANGED_ATTACK
);
2502 setAttackTimer( RANGED_ATTACK
, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
);
2505 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_IDLE
);
2507 else if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_IDLE
&& isAttackReady(RANGED_ATTACK
) )
2509 // check if we can cast
2510 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast() == 0)
2512 // check movement in player case
2513 if(GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving())
2515 // cancel wand shooting
2516 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2517 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2518 // ELSE delay auto-repeat ranged weapon until player movement stop
2521 // recheck range and req. items (ammo and gun, etc)
2522 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CheckRange() == 0 && m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CheckItems() == 0 )
2524 // check, if we are casting melee spell (it blocks autorepeat)
2525 if ( ! (m_currentSpells
[CURRENT_MELEE_SPELL
] &&
2526 (m_currentSpells
[CURRENT_MELEE_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2527 (m_currentSpells
[CURRENT_MELEE_SPELL
]->getState() != SPELL_STATE_DELAYED
)) )
2529 // check, if we are casting something else, if no then run autorepeat spell
2530 if (!IsNonMeleeSpellCasted(false, false, true))
2532 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_PREPARING
);
2533 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->ReSetTimer();
2539 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2544 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2547 else if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_PREPARING
)
2549 // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
2550 if ( m_currentSpells
[CURRENT_MELEE_SPELL
] ||
2551 m_currentSpells
[CURRENT_GENERIC_SPELL
] ||
2552 m_currentSpells
[CURRENT_CHANNELED_SPELL
] ||
2553 !isAttackReady(RANGED_ATTACK
) )
2555 // some other spell is here or ranged attack is not ready, break us to idle state
2556 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->finish(false);
2557 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_IDLE
);
2562 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
2564 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2566 uint32 CSpellType
= pSpell
->GetCurrentContainer();
2568 pSpell
->SetDeletable(false); // spell will not be deleted until gone from current pointers
2569 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
2571 // break same type spell if it is not delayed
2572 if ( m_currentSpells
[CSpellType
] &&
2573 m_currentSpells
[CSpellType
]->getState() != SPELL_STATE_DELAYED
)
2575 InterruptSpell(CSpellType
);
2578 // special breakage effects:
2581 case CURRENT_GENERIC_SPELL
:
2583 // generic spells always break channeled not delayed spells
2584 if ( m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
2585 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_DELAYED
)
2587 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2590 // autorepeat breaking
2591 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
2593 // break autorepeat if not Auto Shot
2594 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2595 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2599 case CURRENT_CHANNELED_SPELL
:
2601 // channel spells always break generic and channeled spells
2602 InterruptSpell(CURRENT_GENERIC_SPELL
);
2603 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2605 // it also does break autorepeat if not Auto Shot
2606 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
2607 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
2608 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2611 case CURRENT_AUTOREPEAT_SPELL
:
2613 // only Auto Shoot does not break anything
2614 if (pSpell
->m_spellInfo
->Category
== 351)
2616 // generic autorepeats break generic and channeled spells
2617 InterruptSpell(CURRENT_GENERIC_SPELL
);
2618 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2622 // special action: set first cast flag for Auto Shoot
2623 m_AutoRepeatFirstCast
= true;
2629 // other spell types don't break anything now
2633 // current spell (if it is still here) may be safely deleted now
2634 if (m_currentSpells
[CSpellType
])
2635 m_currentSpells
[CSpellType
]->SetDeletable(true);
2637 // set new current spell
2638 m_currentSpells
[CSpellType
] = pSpell
;
2641 void Unit::InterruptSpell(uint32 spellType
)
2643 assert(spellType
< CURRENT_MAX_SPELL
);
2645 if(m_currentSpells
[spellType
])
2647 // send autorepeat cancel message for autorepeat spells
2648 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
2650 if(GetTypeId()==TYPEID_PLAYER
)
2651 ((Player
*)this)->SendAutoRepeatCancel();
2654 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
2655 m_currentSpells
[spellType
]->cancel();
2656 m_currentSpells
[spellType
]->SetDeletable(true);
2657 m_currentSpells
[spellType
] = NULL
;
2661 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
)
2663 // We don't do loop here to explicitly show that melee spell is excluded.
2664 // Maybe later some special spells will be excluded too.
2666 // generic spells are casted when they are not finished and not delayed
2667 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
2668 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2669 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2672 // channeled spells may be delayed, but they are still considered casted
2673 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
2674 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
2677 // autorepeat spells may be finished or delayed, but they are still considered casted
2678 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
2684 void Unit::InterruptNonMeleeSpells(bool withDelayed
)
2686 // generic spells are interrupted if they are not finished or delayed
2687 if (m_currentSpells
[CURRENT_GENERIC_SPELL
])
2689 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2690 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2691 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
2692 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetDeletable(true);
2693 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
2696 // autorepeat spells are interrupted if they are not finished or delayed
2697 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
2699 // send disable autorepeat packet in any case
2700 if(GetTypeId()==TYPEID_PLAYER
)
2701 ((Player
*)this)->SendAutoRepeatCancel();
2703 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2704 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2705 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
2706 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetDeletable(true);
2707 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
2710 // channeled spells are interrupted if they are not finished, even if they are delayed
2711 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
])
2713 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
2714 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
2715 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetDeletable(true);
2716 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
2720 bool Unit::isInFront(Unit
const* target
, float radius
) const
2722 return IsWithinDistInMap(target
, radius
) && HasInArc( M_PI
, target
);
2725 void Unit::SetInFront(Unit
const* target
)
2727 SetOrientation(GetAngle(target
));
2730 bool Unit::isInAccessablePlaceFor(Creature
* c
) const
2733 return c
->isCanSwimOrFly();
2735 return c
->isCanWalkOrFly();
2738 bool Unit::IsInWater() const
2740 return MapManager::Instance().GetMap(GetMapId(), this)->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
2743 bool Unit::IsUnderWater() const
2745 return MapManager::Instance().GetMap(GetMapId(), this)->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
2748 void Unit::DeMorph()
2750 SetUInt32Value(UNIT_FIELD_DISPLAYID
, GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID
));
2753 long Unit::GetTotalAuraModifier(uint32 ModifierID
) const
2755 uint32 modifier
= 0;
2757 AuraList
const& mTotalAuraList
= GetAurasByType(ModifierID
);
2758 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
2759 modifier
+= (*i
)->GetModifier()->m_amount
;
2764 bool Unit::AddAura(Aura
*Aur
, bool uniq
)
2766 // ghost spell check
2767 if (!isAlive() && !(Aur
->GetSpellProto()->Id
== 20584 || Aur
->GetSpellProto()->Id
== 8326))
2773 if(Aur
->GetTarget() != this)
2775 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
2776 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
2777 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
2782 AuraMap::iterator i
= m_Auras
.find( spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()) );
2784 // take out same spell
2785 if (i
!= m_Auras
.end())
2787 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
2788 if ((*i).second->GetTarget())
2789 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
2790 (*i).second->UpdateAuraDuration();
2793 // passive and persistent auras can stack with themselves any number of times
2794 if (!Aur
->IsPassive() && !Aur
->IsPersistent() && m_Auras
.count(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex())) >= Aur
->GetSpellProto()->StackAmount
)
2798 // passive auras stack with all (except passive spell proc auras)
2799 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
2800 !(Aur
->GetSpellProto()->Id
== 20584 || Aur
->GetSpellProto()->Id
== 8326))
2802 if (!RemoveNoStackAurasDueToAura(Aur
))
2805 return false; // couldnt remove conflicting aura with higher rank
2809 // adding linked auras
2810 // add the shapeshift aura's boosts
2811 if(Aur
->GetModifier()->m_auraname
== SPELL_AURA_MOD_SHAPESHIFT
)
2812 Aur
->HandleShapeshiftBoosts(true);
2815 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
2816 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
2818 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
2819 m_AuraModifiers
[Aur
->GetModifier()->m_auraname
] += (Aur
->GetModifier()->m_amount
);
2822 if (IsSingleTarget(Aur
->GetId()) && Aur
->GetTarget() && Aur
->GetSpellProto())
2824 if(Unit
* caster
= Aur
->GetCaster())
2826 AuraList
& scAuras
= caster
->GetSingleCastAuras();
2827 AuraList::iterator itr
, next
;
2828 for (itr
= scAuras
.begin(); itr
!= scAuras
.end(); itr
= next
)
2832 if ((*itr
)->GetTarget() != Aur
->GetTarget() &&
2833 (*itr
)->GetSpellProto()->Category
== Aur
->GetSpellProto()->Category
&&
2834 (*itr
)->GetSpellProto()->SpellIconID
== Aur
->GetSpellProto()->SpellIconID
&&
2835 (*itr
)->GetSpellProto()->SpellVisual
== Aur
->GetSpellProto()->SpellVisual
&&
2836 (*itr
)->GetSpellProto()->Attributes
== Aur
->GetSpellProto()->Attributes
&&
2837 (*itr
)->GetSpellProto()->AttributesEx
== Aur
->GetSpellProto()->AttributesEx
&&
2838 (*itr
)->GetSpellProto()->AttributesExEx
== Aur
->GetSpellProto()->AttributesExEx
)
2840 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
2844 next
= scAuras
.begin();
2847 scAuras
.push_back(Aur
);
2853 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
2855 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
2858 AuraMap::iterator i
,next
;
2859 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
2863 uint32 i_spellId
= (*i
).second
->GetId();
2864 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
2866 if(objmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
2868 RemoveAurasDueToSpell(i_spellId
);
2870 if( m_Auras
.empty() )
2873 next
= m_Auras
.begin();
2879 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
2884 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
2888 uint32 spellId
= Aur
->GetId();
2889 uint32 effIndex
= Aur
->GetEffIndex();
2890 bool is_sec
= IsSpellSingleEffectPerCaster(spellId
);
2891 AuraMap::iterator i
,next
;
2892 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
2896 if (!(*i
).second
) continue;
2898 if (!(*i
).second
->GetSpellProto())
2901 uint32 i_spellId
= (*i
).second
->GetId();
2903 if(IsPassiveSpell(i_spellId
))
2905 if(IsPassiveStackableSpell(i_spellId
))
2908 // passive non-stackable spells not stackable only with another rank of same spell
2909 if (!objmgr
.IsRankSpellDueToSpell(Aur
->GetSpellProto(), i_spellId
))
2913 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
2915 if(i_spellId
== spellId
) continue;
2917 bool is_triggered_by_spell
= false;
2918 // prevent triggered aura of removing aura that triggered it
2919 for(int j
= 0; j
< 3; ++j
)
2920 if ((*i
).second
->GetSpellProto()->EffectTriggerSpell
[j
] == spellProto
->Id
)
2921 is_triggered_by_spell
= true;
2922 if (is_triggered_by_spell
) continue;
2924 // prevent remove dummy triggered spells at next effect aura add
2925 for(int j
= 0; j
< 3; ++j
)
2927 switch(spellProto
->Effect
[j
])
2929 case SPELL_EFFECT_DUMMY
:
2932 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
2936 if(is_triggered_by_spell
)
2939 switch(spellProto
->EffectApplyAuraName
[j
])
2941 case SPELL_AURA_MOD_SHAPESHIFT
:
2944 case 33891: if(i_spellId
==5420 || i_spellId
==34123) is_triggered_by_spell
= true; break;
2950 if(!is_triggered_by_spell
)
2952 bool sec_match
= false;
2953 bool is_i_sec
= IsSpellSingleEffectPerCaster(i_spellId
);
2954 if( is_sec
&& is_i_sec
)
2955 if (Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID())
2956 if (GetSpellSpecific(spellId
) == GetSpellSpecific(i_spellId
))
2958 if( sec_match
|| objmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) && !is_sec
&& !is_i_sec
)
2960 // if sec_match this isn't always true, needs to be rechecked
2961 if (objmgr
.IsRankSpellDueToSpell(Aur
->GetSpellProto(), i_spellId
))
2962 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
2963 return false; // cannot remove higher rank
2965 RemoveAurasDueToSpell(i_spellId
);
2967 if( m_Auras
.empty() )
2970 next
= m_Auras
.begin();
2972 else // Potions stack aura by aura
2973 if (Aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_POTION
&&
2974 (*i
).second
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_POTION
)
2976 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
2978 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
2979 return false; // cannot remove higher rank
2990 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type
, Unit
*pCaster
)
2992 AuraMap::iterator i
;
2993 for (i
= m_Auras
.begin(); i
!= m_Auras
.end();)
2995 if ((*i
).second
&& (*i
).second
->GetSpellProto()->Dispel
== dispel_type
)
2997 if(dispel_type
== 1)
2999 bool positive
= true;
3000 switch((*i
).second
->GetSpellProto()->EffectImplicitTargetA
[(*i
).second
->GetEffIndex()])
3002 case TARGET_CHAIN_DAMAGE
:
3003 case TARGET_ALL_ENEMY_IN_AREA
:
3004 case TARGET_ALL_ENEMY_IN_AREA_INSTANT
:
3005 case TARGET_ALL_ENEMIES_AROUND_CASTER
:
3006 case TARGET_IN_FRONT_OF_CASTER
:
3007 case TARGET_DUELVSPLAYER
:
3008 case TARGET_ALL_ENEMY_IN_AREA_CHANNELED
:
3009 case TARGET_CURRENT_SELECTED_ENEMY
:
3014 positive
= ((*i
).second
->GetSpellProto()->AttributesEx
& (1<<7)) ? false : true;
3016 if(positive
&& IsFriendlyTo(pCaster
)) // PBW
3030 void Unit::RemoveAreaAurasByOthers(uint64 guid
)
3033 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3035 if (i
->second
&& i
->second
->IsAreaAura())
3037 uint64 casterGuid
= i
->second
->GetCasterGUID();
3038 uint64 targetGuid
= i
->second
->GetTarget()->GetGUID();
3039 // if area aura cast by someone else or by the specified caster
3040 if (casterGuid
== guid
|| (guid
== 0 && casterGuid
!= targetGuid
))
3042 for (j
= 0; j
< 4; j
++)
3043 if (m_TotemSlot
[j
] == casterGuid
)
3045 // and not by one of my totems
3059 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
)
3061 AuraMap::iterator iter
;
3062 while((iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
))) != m_Auras
.end())
3066 void Unit::RemoveAurasDueToSpell(uint32 spellId
)
3068 for (int i
= 0; i
< 3; ++i
)
3069 RemoveAura(spellId
,i
);
3072 void Unit::RemoveAurasDueToItem(Item
* castItem
)
3074 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3076 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
3083 void Unit::RemoveAura(AuraMap::iterator
&i
, bool onDeath
)
3085 if (IsSingleTarget((*i
).second
->GetId()))
3087 if(Unit
* caster
= (*i
).second
->GetCaster())
3089 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3090 scAuras
.remove((*i
).second
);
3093 sLog
.outError("Unit::RemoveAura: cannot remove the single cast aura from the caster, potential crash!");
3095 // remove aura from party members when the caster turns off the aura
3096 if((*i
).second
->IsAreaAura())
3098 Unit
*i_target
= (*i
).second
->GetTarget();
3099 if((*i
).second
->GetCasterGUID() == i_target
->GetGUID())
3101 Unit
* i_caster
= i_target
;
3104 Group
*pGroup
= NULL
;
3105 Player
*pGroupOf
= NULL
;
3106 if (i_caster
->GetTypeId() == TYPEID_PLAYER
)
3108 pGroupOf
= (Player
*)i_caster
;
3109 pGroup
= pGroupOf
->GetGroup();
3111 else if(((Creature
*)i_caster
)->isTotem() || ((Creature
*)i_caster
)->isPet() || i_caster
->isCharmed())
3113 owner
= i_caster
->GetCharmerOrOwner();
3114 if (owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
3116 pGroupOf
= (Player
*)owner
;
3117 pGroup
= pGroupOf
->GetGroup();
3121 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
3122 if(pGroup
&& pGroupOf
)
3124 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
3126 Player
* Target
= itr
->getSource();
3127 if(!Target
|| !pGroup
->SameSubGroup(pGroupOf
, Target
))
3130 if(Target
->GetGUID() == i_caster
->GetGUID())
3132 Aura
*t_aura
= Target
->GetAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3134 if (t_aura
->GetCasterGUID() == i_caster
->GetGUID())
3135 Target
->RemoveAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3140 Aura
*t_aura
= owner
->GetAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3142 if (t_aura
->GetCasterGUID() == i_caster
->GetGUID())
3143 owner
->RemoveAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3147 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3149 m_AuraModifiers
[(*i
).second
->GetModifier()->m_auraname
] -= ((*i
).second
->GetModifier()->m_amount
);
3150 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
3152 (*i
).second
->SetRemoveOnDeath(onDeath
);
3154 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3155 Aura
* Aur
= i
->second
;
3157 DiminishingMechanics mech
= DIMINISHING_NONE
;
3158 if(Aur
->GetSpellProto()->Mechanic
)
3160 mech
= Unit::Mechanic2DiminishingMechanics(Aur
->GetSpellProto()->Mechanic
);
3161 if(mech
== DIMINISHING_MECHANIC_STUN
|| GetTypeId() == TYPEID_PLAYER
&& mech
!= DIMINISHING_NONE
)
3162 UpdateDiminishingTime(mech
);
3165 // must remove before removing from list (its remove dependent auras and _i_ is only safe iterator value
3166 // remove the shapeshift aura's boosts
3167 if(Aur
->GetModifier()->m_auraname
== SPELL_AURA_MOD_SHAPESHIFT
)
3168 Aur
->HandleShapeshiftBoosts(false);
3171 m_removedAuras
++; // internal count used by unit update
3176 // only way correctly remove all auras from list
3177 if( m_Auras
.empty() )
3180 i
= m_Auras
.begin();
3183 bool Unit::SetAurDuration(uint32 spellId
, uint32 effindex
,uint32 duration
)
3185 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3186 if (iter
!= m_Auras
.end())
3188 (*iter
).second
->SetAuraDuration(duration
);
3189 (*iter
).second
->UpdateAuraDuration();
3195 uint32
Unit::GetAurDuration(uint32 spellId
, uint32 effindex
)
3197 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3198 if (iter
!= m_Auras
.end())
3200 return (*iter
).second
->GetAuraDuration();
3205 void Unit::RemoveAllAuras()
3207 while (!m_Auras
.empty())
3209 AuraMap::iterator iter
= m_Auras
.begin();
3214 void Unit::RemoveAllAurasOnDeath()
3216 // used just after dieing to remove all visible auras
3217 // and disable the mods for the passive ones
3218 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
3220 if (!iter
->second
->IsPassive())
3221 RemoveAura(iter
, true);
3227 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
3229 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3230 if (iter
!= m_Auras
.end())
3232 if (iter
->second
->GetAuraDuration() < delaytime
)
3233 iter
->second
->SetAuraDuration(0);
3235 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
3236 iter
->second
->UpdateAuraDuration();
3237 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
3241 void Unit::_RemoveAllAuraMods()
3243 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3245 (*i
).second
->ApplyModifier(false);
3249 void Unit::_ApplyAllAuraMods()
3251 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3253 (*i
).second
->ApplyModifier(true);
3258 /*void Unit::_UpdateAura()
3260 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
3263 Player* pThis = (Player*)this;
3268 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
3270 if(!SetAffDuration(m_Auras->GetId(),this,6000))
3277 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
3279 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
3283 if(pGroupGuy->GetGUID() == GetGUID())
3286 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
3287 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
3288 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
3291 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
3292 pGroupGuy->AddAura(m_Auras);
3296 if(m_removeAuraTimer == 0)
3298 printf("remove aura from %u\n", pGroupGuy->GetGUID());
3299 pGroupGuy->RemoveAura(m_Auras->GetId());
3304 if(m_removeAuraTimer > 0)
3305 m_removeAuraTimer -= 1;
3307 m_removeAuraTimer = 4;
3310 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
3312 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3313 if (iter
!= m_Auras
.end())
3314 return iter
->second
;
3318 void Unit::AddDynObject(DynamicObject
* dynObj
)
3320 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
3323 void Unit::RemoveDynObject(uint32 spellid
)
3325 if(m_dynObjGUIDs
.empty())
3327 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
3329 DynamicObject
* dynObj
= ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
3332 i
= m_dynObjGUIDs
.erase(i
);
3334 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
3337 i
= m_dynObjGUIDs
.erase(i
);
3344 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
3346 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
3348 DynamicObject
* dynObj
= ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
3351 i
= m_dynObjGUIDs
.erase(i
);
3355 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
3362 void Unit::AddGameObject(GameObject
* gameObj
)
3364 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
3365 m_gameObj
.push_back(gameObj
);
3366 gameObj
->SetOwnerGUID(GetGUID());
3369 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
3371 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
3372 gameObj
->SetOwnerGUID(0);
3373 m_gameObj
.remove(gameObj
);
3376 gameObj
->SetRespawnTime(0);
3381 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
3383 if(m_gameObj
.empty())
3385 std::list
<GameObject
*>::iterator i
, next
;
3386 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
3389 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
3391 (*i
)->SetOwnerGUID(0);
3394 (*i
)->SetRespawnTime(0);
3398 next
= m_gameObj
.erase(i
);
3405 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchools DamageType
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
3407 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+31)); // we guess size
3408 data
.append(target
->GetPackGUID());
3409 data
.append(GetPackGUID());
3410 data
<< uint32(SpellID
);
3411 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
3412 data
<< uint8(DamageType
); //damagetype
3413 data
<< uint32(AbsorbedDamage
); //AbsorbedDamage
3414 data
<< uint32(Resist
); //resist
3415 data
<< (uint8
)PhysicalDamage
;
3417 data
<< uint32(Blocked
); //blocked
3418 data
<< uint8(CriticalHit
? 2 : 0); //seen 0x05 also...
3420 SendMessageToSet( &data
, true );
3423 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchools DamageType
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, uint32 TargetState
, uint32 BlockedAmount
)
3425 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
3427 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
3428 data
<< (uint32
)HitInfo
;
3429 data
.append(GetPackGUID());
3430 data
.append(target
->GetPackGUID());
3431 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3433 data
<< (uint8
)SwingType
;
3434 data
<< (uint32
)DamageType
;
3437 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3438 // still need to double check damaga
3439 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3440 data
<< (uint32
)AbsorbDamage
;
3441 data
<< (uint32
)Resist
;
3442 data
<< (uint32
)TargetState
;
3444 if( AbsorbDamage
== 0 ) //also 0x3E8 = 0x3E8, check when that happens
3450 data
<< (uint32
)BlockedAmount
;
3452 SendMessageToSet( &data
, true );
3455 struct ProcTriggeredData
3457 ProcTriggeredData(SpellEntry
const * _spellInfo
, uint32 _spellParam
, Aura
* _triggeredByAura
)
3458 : spellInfo(_spellInfo
), spellParam(_spellParam
), triggeredByAura(_triggeredByAura
) {}
3460 SpellEntry
const * spellInfo
;
3462 Aura
* triggeredByAura
;
3465 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
3467 // used to prevent spam in log about same non-handled spells
3468 static std::set
<uint32
> nonHandledSpellProcSet
;
3470 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
3472 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
3474 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
3476 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
3477 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
3478 // That is the question though if it's fully correct
3479 if(procSpell
&& !isTriggeredSpell
)
3481 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
3483 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
3484 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
3485 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
3486 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
3487 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
3489 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
3491 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
3492 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
3493 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
3494 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
3495 attType
= RANGED_ATTACK
;
3498 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
3499 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
3501 // Not much to do if no flags are set.
3504 for(std::set
<uint32
>::iterator aur
= attackerProcAuraTypes
.begin(); aur
!= attackerProcAuraTypes
.end(); ++aur
)
3506 // List of spells (effects) that proced. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3507 ProcTriggeredList procTriggered
;
3509 AuraList
const& attackerAuras
= GetAurasByType(*aur
);
3510 for(AuraList::const_iterator i
= attackerAuras
.begin(), next
; i
!= attackerAuras
.end(); i
= next
)
3513 uint32 procFlag
= procAttacker
;
3515 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
3516 if(!spellProto
) continue;
3517 SpellProcEventEntry
const *spellProcEvent
= objmgr
.GetSpellProcEvent(spellProto
->Id
);
3519 if(!spellProcEvent
&& spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
3521 sLog
.outError("ProcDamageAndSpell: spell %u (attacker's aura source) not have record in `spell_proc_event`)",spellProto
->Id
);
3522 nonHandledSpellProcSet
.insert(spellProto
->Id
);
3525 uint32 procFlags
= spellProcEvent
? spellProcEvent
->procFlags
: spellProto
->procFlags
;
3526 // Check if current equipment allows aura to proc
3527 if(GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->IsUseEquipedWeapon())
3529 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
3532 if(attType
== BASE_ATTACK
)
3533 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
3534 else if (attType
== OFF_ATTACK
)
3535 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3537 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_RANGED
);
3539 if(!item
|| item
->IsBroken() || item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
3542 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
3544 // Check if player is wearing shield
3545 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
3546 if(!item
|| item
->IsBroken() || item
->GetProto()->Class
!= ITEM_CLASS_ARMOR
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
3550 if((procFlag
& procFlags
) == 0)
3553 // Additional checks in case spell cast/hit/crit is the event
3554 // Check (if set) school, category, skill line, spell talent mask
3557 if(spellProcEvent
->schoolMask
&& (!procSpell
|| !procSpell
->School
|| ((1<<procSpell
->School
) & spellProcEvent
->schoolMask
) == 0))
3559 if(spellProcEvent
->category
&& (!procSpell
|| procSpell
->Category
!= spellProcEvent
->category
))
3561 if(spellProcEvent
->skillId
)
3563 if (!procSpell
) continue;
3564 SkillLineAbilityEntry
const *skillLineEntry
= sSkillLineAbilityStore
.LookupEntry(procSpell
->Id
);
3565 if(!skillLineEntry
|| skillLineEntry
->skillId
!= spellProcEvent
->skillId
)
3568 if(spellProcEvent
->spellFamilyName
&& (!procSpell
|| spellProcEvent
->spellFamilyName
!= procSpell
->SpellFamilyName
))
3570 if(spellProcEvent
->spellFamilyMask
&& (!procSpell
|| (spellProcEvent
->spellFamilyMask
& procSpell
->SpellFamilyFlags
) == 0))
3574 // Need to use floats here, cuz calculated PPM chance often is about 1-2%
3575 float chance
= (float)spellProto
->procChance
;
3576 if(GetTypeId() == TYPEID_PLAYER
)
3577 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
3578 uint32 WeaponSpeed
= GetAttackTime(attType
);
3579 if(spellProcEvent
&& spellProcEvent
->ppmRate
!= 0)
3580 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
3582 if(roll_chance_f(chance
))
3584 if((*i
)->m_procCharges
> 0)
3585 (*i
)->m_procCharges
-= 1;
3587 uint32 i_spell_eff
= (*i
)->GetEffIndex();
3589 int32 i_spell_param
;
3592 case SPELL_AURA_PROC_TRIGGER_SPELL
: i_spell_param
= procFlag
; break;
3593 case SPELL_AURA_DUMMY
: i_spell_param
= i_spell_eff
; break;
3594 default: i_spell_param
= (*i
)->GetModifier()->m_amount
; break;
3597 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
) );
3601 // Handle effects proceed this time
3602 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); i
++)
3604 if(*aur
== SPELL_AURA_PROC_TRIGGER_SPELL
)
3606 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by an attacker's aura of spell %u)", i
->spellInfo
->Id
,i
->triggeredByAura
->GetId());
3607 HandleProcTriggerSpell(pVictim
, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
);
3609 else if(*aur
== SPELL_AURA_PROC_TRIGGER_DAMAGE
)
3611 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by an attacker's aura of spell %u)", i
->spellParam
, i
->spellInfo
->Id
,i
->triggeredByAura
->GetId());
3612 uint32 damage
= i
->spellParam
;
3613 // TODO: remove hack for Seal of Righteousness. That should not be there
3614 if(i
->spellInfo
->SpellVisual
== 7986)
3615 damage
= (damage
* GetAttackTime(BASE_ATTACK
))/60/1000;
3616 if(pVictim
&& pVictim
->isAlive())
3617 SpellNonMeleeDamageLog(pVictim
, i
->spellInfo
->Id
, damage
, true, true);
3619 else if(*aur
== SPELL_AURA_DUMMY
)
3621 // TODO: write a DUMMY aura handle code
3622 if (pVictim
&& pVictim
->isAlive())
3624 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by an attacker dummy aura of spell %u)", i
->spellInfo
->Id
,i
->triggeredByAura
->GetId());
3625 HandleDummyAuraProc(pVictim
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procAttacker
);
3630 // Safely remove attacker auras with zero charges
3631 for(AuraList::const_iterator i
= attackerAuras
.begin(), next
; i
!= attackerAuras
.end(); i
= next
)
3634 if((*i
)->m_procCharges
== 0)
3636 RemoveAurasDueToSpell((*i
)->GetId());
3637 next
= attackerAuras
.begin();
3643 // Now go on with a victim's events'n'auras
3644 // Not much to do if no flags are set or there is no victim
3645 if(pVictim
&& pVictim
->isAlive() && procVictim
)
3647 for(std::set
<uint32
>::iterator aur
= victimProcAuraTypes
.begin(); aur
!= victimProcAuraTypes
.end(); aur
++)
3649 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
3650 ProcTriggeredList procTriggered
;
3652 AuraList
const& victimAuras
= pVictim
->GetAurasByType(*aur
);
3653 for(AuraList::const_iterator i
= victimAuras
.begin(), next
; i
!= victimAuras
.end(); i
= next
)
3656 uint32 procFlag
= procVictim
;
3658 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
3659 if(!spellProto
) continue;
3660 SpellProcEventEntry
const *spellProcEvent
= objmgr
.GetSpellProcEvent(spellProto
->Id
);
3662 if(!spellProcEvent
&& spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
3664 sLog
.outError("ProcDamageAndSpell: spell %u (victim's aura source) not have record in `spell_proc_event`)",spellProto
->Id
);
3665 nonHandledSpellProcSet
.insert(spellProto
->Id
);
3668 uint32 procFlags
= spellProcEvent
? spellProcEvent
->procFlags
: spellProto
->procFlags
;
3669 if((procFlag
& procFlags
) == 0)
3672 // Additional checks in case spell cast/hit/crit is the event
3673 // Check (if set) school, category, skill line, spell talent mask
3676 if(spellProcEvent
->schoolMask
&& (!procSpell
|| !procSpell
->School
|| ((1<<procSpell
->School
) & spellProcEvent
->schoolMask
) == 0))
3678 if(spellProcEvent
->category
&& (!procSpell
|| procSpell
->Category
!= spellProcEvent
->category
))
3680 if(spellProcEvent
->skillId
)
3682 if (!procSpell
) continue;
3683 SkillLineAbilityEntry
const *skillLineEntry
= sSkillLineAbilityStore
.LookupEntry(procSpell
->Id
);
3684 if(!skillLineEntry
|| skillLineEntry
->skillId
!= spellProcEvent
->skillId
)
3687 if(spellProcEvent
->spellFamilyName
&& (!procSpell
|| spellProcEvent
->spellFamilyName
!= procSpell
->SpellFamilyName
))
3689 if(spellProcEvent
->spellFamilyMask
&& (!procSpell
|| (spellProcEvent
->spellFamilyMask
& procSpell
->SpellFamilyFlags
) == 0))
3693 // procChance is exact number in percents anyway
3694 uint32 chance
= spellProto
->procChance
;
3695 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
3696 ((Player
*)pVictim
)->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
3697 if(roll_chance_i(chance
))
3699 if((*i
)->m_procCharges
> 0)
3700 (*i
)->m_procCharges
-= 1;
3702 uint32 i_spell_eff
= (*i
)->GetEffIndex();
3703 int32 i_spell_param
;
3706 case SPELL_AURA_PROC_TRIGGER_SPELL
: i_spell_param
= procFlag
; break;
3707 case SPELL_AURA_DUMMY
: i_spell_param
= i_spell_eff
; break;
3708 default: i_spell_param
= (*i
)->GetModifier()->m_amount
; break;
3711 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
) );
3715 // Handle effects proced this time
3716 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); i
++)
3718 if(*aur
== SPELL_AURA_PROC_TRIGGER_SPELL
)
3720 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's aura of spell %u))",i
->spellInfo
->Id
, i
->triggeredByAura
);
3721 pVictim
->HandleProcTriggerSpell(this, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
);
3723 else if(*aur
== SPELL_AURA_PROC_TRIGGER_DAMAGE
)
3725 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by a victim's aura of spell %u))", i
->spellParam
, i
->spellInfo
->Id
, i
->triggeredByAura
);
3726 pVictim
->SpellNonMeleeDamageLog(this, i
->spellInfo
->Id
, i
->spellParam
, true, true);
3728 else if(*aur
== SPELL_AURA_DUMMY
)
3730 // TODO: write a DUMMY aura handle code
3731 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by a victim's dummy aura of spell %u))",i
->spellInfo
->Id
, i
->triggeredByAura
);
3732 pVictim
->HandleDummyAuraProc(this, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procVictim
);
3736 // Safely remove auras with zero charges
3737 for(AuraList::const_iterator i
= victimAuras
.begin(), next
; i
!= victimAuras
.end(); i
= next
)
3740 if((*i
)->m_procCharges
== 0)
3742 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
3743 next
= victimAuras
.begin();
3750 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
3755 uint32 procAttacker
= PROC_FLAG_NONE
;
3756 uint32 procVictim
= PROC_FLAG_NONE
;
3760 case MELEE_HIT_MISS
:
3761 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3763 procAttacker
= PROC_FLAG_MISS
;
3766 case MELEE_HIT_CRIT
:
3767 if(spellCasted
&& attType
== BASE_ATTACK
)
3769 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
3770 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
3772 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3774 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
3775 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
3779 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
3780 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
3783 case MELEE_HIT_PARRY
:
3784 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
3785 procVictim
= PROC_FLAG_PARRY
;
3787 case MELEE_HIT_BLOCK
:
3788 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
3789 procVictim
= PROC_FLAG_BLOCK
;
3791 case MELEE_HIT_DODGE
:
3792 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
3793 procVictim
= PROC_FLAG_DODGE
;
3795 case MELEE_HIT_CRUSHING
:
3796 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3798 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
3799 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
3803 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
3804 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
3808 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3810 procAttacker
= PROC_FLAG_HIT_MELEE
;
3811 procVictim
= PROC_FLAG_STRUCK_MELEE
;
3815 procAttacker
= PROC_FLAG_HIT_RANGED
;
3816 procVictim
= PROC_FLAG_STRUCK_RANGED
;
3822 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
3824 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
3825 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, spellCasted
, isTriggeredSpell
, attType
);
3828 void Unit::HandleDummyAuraProc(Unit
*pVictim
, SpellEntry
const *dummySpell
, uint32 effIndex
, uint32 damage
, Aura
* triggredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
)
3830 switch(dummySpell
->Id
)
3842 int32 igniteDotBasePoints0
;
3844 switch (dummySpell
->Id
)
3846 case 11119: igniteDotBasePoints0
=int32(0.04f
*damage
)-1; break;
3847 case 11120: igniteDotBasePoints0
=int32(0.08f
*damage
)-1; break;
3848 case 12846: igniteDotBasePoints0
=int32(0.12f
*damage
)-1; break;
3849 case 12847: igniteDotBasePoints0
=int32(0.16f
*damage
)-1; break;
3850 case 12848: igniteDotBasePoints0
=int32(0.20f
*damage
)-1; break;
3852 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
3855 CastCustomSpell(pVictim
, 12654, &igniteDotBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3862 CastSpell(this, 28682, true, NULL
, triggredByAura
);
3863 if (!(procFlag
& PROC_FLAG_CRIT_SPELL
)) //no crit
3864 triggredByAura
->m_procCharges
+= 1; //-> reincrease procCharge count since it was decreased before
3865 else if (triggredByAura
->m_procCharges
== 0) //no more charges left and crit
3866 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
3873 CastSpell(this, 17941, true, NULL
, triggredByAura
);
3882 if(triggredByAura
->GetCasterGUID() == pVictim
->GetGUID())
3884 //VEHeal has a BaseDice of 0, so no decrement needed
3885 int32 VEHealBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100;
3886 pVictim
->CastCustomSpell(pVictim
, 15290, &VEHealBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3897 // return damage % to attacker but < 50% own total health
3898 uint32 backDamage
= triggredByAura
->GetModifier()->m_amount
*damage
/100;
3899 if(backDamage
> GetMaxHealth()/2)
3900 backDamage
= GetMaxHealth()/2;
3902 int32 YYDamageBasePoints0
= backDamage
-1;
3903 CastCustomSpell(pVictim
, 25997, &YYDamageBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3918 // we assume lightning bolt and chain lightning are generic (not channeled/autorepeat) spells
3919 if(!pVictim
|| !m_currentSpells
[CURRENT_GENERIC_SPELL
])
3922 // remove cooldown from first cast
3923 if(GetTypeId()==TYPEID_PLAYER
)
3924 ((Player
*)this)->RemoveSpellCooldown(procSpell
->Id
);
3925 // prepare cast as triggered spell (this need for correct targets selection after not finished currently cast)
3926 m_currentSpells
[CURRENT_GENERIC_SPELL
]->AddTriggeredSpell(procSpell
);
3936 // if healed by another unit (pVictim)
3939 int32 SAHealBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100-1;
3940 CastCustomSpell(this, 31786, &SAHealBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3946 // Shadowflame (item set effect)
3949 if(GetTypeId() != TYPEID_PLAYER
)
3952 Item
* castItem
= ((Player
*)this)->GetItemByGuid(triggredByAura
->GetCastItemGUID());
3956 CastSpell(pVictim
,37379,true,castItem
,triggredByAura
);
3959 // Shadowflame Hellfire (item set effect)
3962 if(GetTypeId() != TYPEID_PLAYER
)
3965 Item
* castItem
= ((Player
*)this)->GetItemByGuid(triggredByAura
->GetCastItemGUID());
3969 CastSpell(pVictim
,37378,true,castItem
,triggredByAura
);
3976 switch(dummySpell
->SpellFamilyName
)
3978 case SPELLFAMILY_SHAMAN
:
3979 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
3981 int32 HealBasePoints0
= dummySpell
->EffectBasePoints
[0];
3982 CastCustomSpell(this,379,&HealBasePoints0
,NULL
,NULL
,true,NULL
,triggredByAura
);
3990 // Non SpellID checks
3991 switch(dummySpell
->SpellIconID
)
3993 // Master of Elements
3999 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_MAGE
)
4002 int32 MEManaCostSave
= procSpell
->manaCost
* triggredByAura
->GetModifier()->m_amount
/100;
4003 if(MEManaCostSave
<= 0)
4005 int32 MEManaRestoreBasePoints0
= MEManaCostSave
-1;
4006 CastCustomSpell(this,29077,&MEManaRestoreBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
4016 if(triggredByAura
->GetCasterGUID() == pVictim
->GetGUID())
4018 int32 VTEnergizeBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100 - 1;
4019 pVictim
->CastCustomSpell(pVictim
,34919,&VTEnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
4029 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
)
4032 // only rogue's finishing moves (maybe need additional checks)
4033 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
4034 (procSpell
->SpellFamilyFlags
& (0x40000 | 0x80000 | 0x100000 | 0x200000 | 0x800000000LL
| 0x20000)) == 0)
4037 int32 QREnegyCostSave
= procSpell
->manaCost
* triggredByAura
->GetModifier()->m_amount
/100;
4038 if(QREnegyCostSave
<= 0)
4040 int32 QREnergizeBasePoints0
= QREnegyCostSave
-1;
4041 CastCustomSpell(this,31663,&QREnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
4045 // Thrill of the Hunt
4051 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_HUNTER
)
4054 int32 THManaCostSave
= procSpell
->manaCost
* 40/100;
4055 if(THManaCostSave
<= 0)
4057 int32 THEnergizeBasePoints0
= THManaCostSave
-1;
4058 CastCustomSpell(this,34720,&THEnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
4065 void Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
)
4067 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
4069 switch(auraSpellInfo
->SpellIconID
)
4073 switch(auraSpellInfo
->SpellFamilyName
)
4075 case SPELLFAMILY_SHAMAN
:
4077 //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
4078 if(auraSpellInfo
->SpellFamilyFlags
==0x00000400)
4084 switch(triggeredByAura
->GetSpellProto()->Id
)
4087 case 324: spell
= 26364; break;
4089 case 325: spell
= 26365; break;
4091 case 905: spell
= 26366; break;
4093 case 945: spell
= 26367; break;
4095 case 8134: spell
= 26369; break;
4097 case 10431: spell
= 26370; break;
4099 case 10432: spell
= 26363; break;
4101 case 25469: spell
= 26371; break;
4103 case 25472: spell
= 26372; break;
4105 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
4108 CastSpell(pVictim
, spell
, true, NULL
, triggeredByAura
);
4113 case SPELLFAMILY_PRIEST
:
4115 // Priest's "Shadowguard"
4116 if(auraSpellInfo
->SpellFamilyFlags
==0x100080000000LL
)
4122 switch(triggeredByAura
->GetSpellProto()->Id
)
4125 case 18137: spell
= 28377; break;
4127 case 19308: spell
= 28378; break;
4129 case 19309: spell
= 28379; break;
4131 case 19310: spell
= 28380; break;
4133 case 19311: spell
= 28381; break;
4135 case 19312: spell
= 28382; break;
4137 case 25477: spell
= 28385; break;
4139 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
4142 CastSpell(pVictim
, spell
, true, NULL
, triggeredByAura
);
4152 //Mana Surge (Shaman T1 bonus)
4157 int32 manaSurgeSpellBasePoints0
= procSpell
->manaCost
* 35/100;
4158 CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4163 //Improved Drain Soul
4165 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
4166 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
4168 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
4170 int32 impDrainSoulBasePoints0
= (*i
)->GetSpellProto()->EffectBasePoints
[2] * GetMaxPower(POWER_MANA
) / 100;
4171 CastCustomSpell(this, 18371, &impDrainSoulBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4178 switch(auraSpellInfo
->EffectTriggerSpell
[0])
4186 SpellEntry
const *originalSpell
= procSpell
;
4188 // in case HShock procspell is triggered spell but we need mana cost of original casted spell
4189 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& procSpell
->SpellFamilyFlags
== 0x00200000)
4191 uint32 originalSpellId
= 0;
4192 switch(procSpell
->Id
)
4194 case 25914: originalSpellId
= 20473; break;
4195 case 25913: originalSpellId
= 20929; break;
4196 case 25903: originalSpellId
= 20930; break;
4197 case 27175: originalSpellId
= 27174; break;
4198 case 33074: originalSpellId
= 33072; break;
4200 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
4203 SpellEntry
const *HSSpell
= sSpellStore
.LookupEntry(originalSpellId
);
4206 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId
);
4209 originalSpell
= HSSpell
;
4212 // percent stored in effect 1 (class scripts) base points
4213 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
4215 // BasePoints = val -1 not required (EffectBaseDice==0)
4216 int32 ILManaSpellBasePoints0
= originalSpell
->manaCost
*percent
/100;
4217 CastCustomSpell(this, 20272, &ILManaSpellBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4225 //Improved Leader of the Pack
4228 if (triggeredByAura
->GetModifier()->m_amount
== 0)
4230 int32 improvedLotPBasePoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100 - 1;
4231 CastCustomSpell(this, 34299, &improvedLotPBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4232 if (GetTypeId() == TYPEID_PLAYER
)
4233 ((Player
*)this)->AddSpellCooldown(34299,0,time(NULL
) + 6);
4241 switch (triggeredByAura
->GetSpellProto()->Id
)
4250 if (pVictim
&& pVictim
->isAlive() && roll_chance_f(chance
))
4251 CastSpell(pVictim
, 18093, true, NULL
, triggeredByAura
);
4257 uint32 EffectId
= 0;
4258 switch (triggeredByAura
->GetSpellProto()->Id
)
4260 case 27811: EffectId
= 27813; break;
4261 case 27815: EffectId
= 27817; break;
4262 case 27816: EffectId
= 27818; break;
4264 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
4268 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
4269 int32 BRHealBasePoints0
= heal_amount
/3-1;
4270 CastCustomSpell(this, EffectId
, &BRHealBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4275 //Effects: 30029(Rank 1), 30031(Rank 2), 30032(Rank 3)
4276 //Check EffectTriggerSpell[1] to determine correct effect id
4277 //CastSpell(this, triggredByAura->GetSpellProto()->EffectTriggerSpell[1], true, NULL, triggredByAura);
4282 //Effects: 31616, 39301
4284 /*float HealthRatio = GetHealth() / GetMaxHealth();
4285 float HealthRatioBefore = (GetHealth() + damage) / GetMaxHealth();
4286 if (HealthRatio < 0.3 && HealthRatioBefore >= 0.3)
4288 SpellEntry const *NGHealTemplate = sSpellStore.LookupEntry(31616);
4289 SpellEntry NGHeal = *NGHealTemplate;
4290 NGHeal.EffectBasePoints[0] = triggredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
4291 CastSpell(this, &NGHeal, true, NULL, triggredByAura);
4292 if (pVictim && pVictim->isAlive())
4293 CastSpell(pVictim, 39301, true, NULL, triggredByAura);
4294 if (GetTypeId() == TYPEID_PLAYER)
4296 ((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
4297 ((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
4305 CastSpell(this, 31643, true, NULL
, triggeredByAura
);
4309 // custom check for proc spell
4310 switch(auraSpellInfo
->Id
)
4312 // Lightning Capacitor
4319 CastSpell(this, 37658, true, NULL
, triggeredByAura
);
4323 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
4324 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
4325 if((*itr
)->GetId()==37658)
4328 // release at 3 aura in stack
4331 RemoveAurasDueToSpell(37658);
4332 CastSpell(pVictim
, 37661, true, NULL
, triggeredByAura
);
4338 // standard non-dummy case
4339 uint32 trigger_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
4340 if(!trigger_spell_id
)
4342 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
4346 // but with dummy basepoints or other customs
4347 switch(trigger_spell_id
)
4349 // Shamanistic Rage triggered spell
4352 int32 SRBasePoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100) -1;
4353 CastCustomSpell(this, 30824, &SRBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4356 // Backlash triggered spell
4359 // need set custom cooldown
4360 if(isAlive() && GetTypeId()==TYPEID_PLAYER
&& !((Player
*)this)->HasSpellCooldown(34936))
4362 CastSpell(this,trigger_spell_id
,true,NULL
,triggeredByAura
);
4363 ((Player
*)this)->AddSpellCooldown(34936,0,time(NULL
)+8);
4370 if(IsPositiveSpell(trigger_spell_id
) && !(procFlags
& PROC_FLAG_HEAL
))
4371 CastSpell(this,trigger_spell_id
,true,NULL
,triggeredByAura
);
4372 else if(pVictim
&& pVictim
->isAlive())
4373 CastSpell(pVictim
,trigger_spell_id
,true,NULL
,triggeredByAura
);
4376 void Unit::setPowerType(Powers new_powertype
)
4378 uint32 tem_bytes_0
= GetUInt32Value(UNIT_FIELD_BYTES_0
);
4379 SetUInt32Value(UNIT_FIELD_BYTES_0
,((tem_bytes_0
<<8)>>8) + (uint32(new_powertype
)<<24));
4381 if (GetTypeId() == TYPEID_PLAYER
)
4382 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
4384 switch(new_powertype
)
4390 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
4391 SetPower( POWER_RAGE
,0);
4394 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
4395 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
4398 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
4399 SetPower( POWER_ENERGY
,0);
4401 case POWER_HAPPINESS
:
4402 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
4403 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
4408 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
4410 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
4413 static uint64 guid
= 0; // prevent repeating spam same faction problem
4415 if(GetGUID() != guid
)
4417 if(GetTypeId() == TYPEID_PLAYER
)
4418 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
4420 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
4427 bool Unit::IsHostileTo(Unit
const* unit
) const
4429 // always non-hostile to self
4433 // always hostile to enemy
4434 if(getVictim()==unit
|| unit
->getVictim()==this)
4437 // test pet/charm masters instead pers/charmeds
4438 Unit
const* testerOwner
= GetCharmerOrOwner();
4439 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
4441 // always hostile to owner's enemy
4442 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
4445 // always hostile to enemy owner
4446 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
4449 // always hostile to owner of owner's enemy
4450 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
4453 Unit
const* tester
= testerOwner
? testerOwner
: this;
4454 Unit
const* target
= targetOwner
? targetOwner
: unit
;
4456 // special cases (Duel, etc)
4457 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
4460 if(((Player
const*)tester
)->duel
&& ((Player
const*)tester
)->duel
->opponent
== target
&& ((Player
const*)tester
)->duel
->startTime
!= 0)
4464 // Green/Blue (can't attack)
4465 if(((Player
*)tester
)->GetTeam()==((Player
*)target
)->GetTeam())
4468 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
4469 return ((Player
*)tester
)->IsPvP() && ((Player
*)target
)->IsPvP();
4472 // faction base cases
4473 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
4474 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
4475 if(!tester_faction
|| !target_faction
)
4478 // PvC forced reaction and reputation case
4479 if(tester
->GetTypeId()==TYPEID_PLAYER
)
4482 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
4483 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
4485 return forceItr
->second
<= REP_HOSTILE
;
4488 // apply reputation state
4489 FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
);
4490 if(raw_target_faction
&& raw_target_faction
->reputationListID
>=0 )
4492 if(((Player
*)tester
)->IsFactionAtWar(raw_target_faction
))
4496 // CvP forced reaction and reputation case
4497 else if(target
->GetTypeId()==TYPEID_PLAYER
)
4500 ForcedReactions::const_iterator forceItr
= ((Player
*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
4501 if(forceItr
!=((Player
*)target
)->m_forcedReactions
.end())
4503 return forceItr
->second
<= REP_HOSTILE
;
4506 // apply reputation state
4507 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
4508 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
4510 return ((Player
*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
4514 // common faction based case (CvC,PvC,CvP)
4515 return tester_faction
->IsHostileTo(*target_faction
);
4518 bool Unit::IsFriendlyTo(Unit
const* unit
) const
4520 // always friendly to self
4524 // always non-friendly to enemy
4525 if(getVictim()==unit
|| unit
->getVictim()==this)
4528 // test pet/charm masters instead pers/charmeds
4529 Unit
const* testerOwner
= GetCharmerOrOwner();
4530 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
4532 // always non-friendly to owner's enemy
4533 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
4536 // always non-friendly to enemy owner
4537 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
4540 // always non-friendly to owner of owner's enemy
4541 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
4544 Unit
const* tester
= testerOwner
? testerOwner
: this;
4545 Unit
const* target
= targetOwner
? targetOwner
: unit
;
4547 // special cases (Duel)
4548 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
4551 if(((Player
const*)tester
)->duel
&& ((Player
const*)tester
)->duel
->opponent
== target
&& ((Player
const*)tester
)->duel
->startTime
!= 0)
4555 // Green/Blue (non-attackable)
4556 if(((Player
*)tester
)->GetTeam()==((Player
*)target
)->GetTeam())
4559 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
4560 return !((Player
*)target
)->IsPvP();
4563 // faction base cases
4564 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
4565 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
4566 if(!tester_faction
|| !target_faction
)
4569 // PvC forced reaction and reputation case
4570 if(tester
->GetTypeId()==TYPEID_PLAYER
)
4573 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
4574 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
4576 return forceItr
->second
>= REP_FRIENDLY
;
4579 // apply reputation state
4580 FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
);
4581 if(raw_target_faction
&& raw_target_faction
->reputationListID
>=0 )
4583 if(((Player
*)tester
)->IsFactionAtWar(raw_target_faction
))
4587 // CvP forced reaction and reputation case
4588 else if(target
->GetTypeId()==TYPEID_PLAYER
)
4591 ForcedReactions::const_iterator forceItr
= ((Player
*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
4592 if(forceItr
!=((Player
*)target
)->m_forcedReactions
.end())
4594 return forceItr
->second
>= REP_FRIENDLY
;
4597 // apply reputation state
4598 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
4599 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
4601 return ((Player
*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
4605 // common faction based case (CvC,PvC,CvP)
4606 return tester_faction
->IsFriendlyTo(*target_faction
);
4609 bool Unit::IsHostileToPlayers() const
4611 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
4615 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
4616 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
4619 return my_faction
->IsHostileToPlayers();
4622 bool Unit::IsNeutralToAll() const
4624 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
4628 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
4629 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
4632 return my_faction
->IsNeutralToAll();
4635 bool Unit::Attack(Unit
*victim
, bool playerMeleeAttack
)
4637 if(!victim
|| victim
== this)
4640 // player don't must attack in mount state
4641 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
4644 // anyone don't must attack GM in GM-mode
4645 if(victim
->GetTypeId()==TYPEID_PLAYER
&& ((Player
*)victim
)->isGameMaster())
4650 if (m_attacking
== victim
)
4656 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
4658 addUnitState(UNIT_STAT_ATTACKING
);
4660 m_attacking
= victim
;
4661 m_attacking
->_addAttacker(this);
4663 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
4664 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
4666 if( GetTypeId()==TYPEID_UNIT
&& !(((Creature
*)this)->isPet() || isCharmed()) )
4668 ((Creature
*)this)->CallAssistence();
4670 //if(!isAttackReady(BASE_ATTACK))
4671 //resetAttackTimer(BASE_ATTACK);
4673 // delay offhand weapon attack to next attack time
4674 if(haveOffhandWeapon())
4675 resetAttackTimer(OFF_ATTACK
);
4677 if(playerMeleeAttack
)
4678 SendAttackStart(victim
);
4683 bool Unit::AttackStop()
4688 Unit
* victim
= m_attacking
;
4690 m_attacking
->_removeAttacker(this);
4694 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
4696 clearUnitState(UNIT_STAT_ATTACKING
);
4698 InterruptSpell(CURRENT_MELEE_SPELL
);
4700 if( GetTypeId()==TYPEID_UNIT
)
4702 // reset call assistance
4703 ((Creature
*)this)->SetNoCallAssistence(false);
4706 SendAttackStop(victim
);
4711 bool Unit::isAttackingPlayer() const
4715 if(getVictim()->GetTypeId() == TYPEID_PLAYER
)
4718 if(getVictim()->GetOwnerGUID() && GUID_HIPART(getVictim()->GetOwnerGUID())==HIGHGUID_PLAYER
)
4722 Pet
* pet
= GetPet();
4723 if(pet
&& pet
->isAttackingPlayer())
4726 Unit
* charmed
= GetCharm();
4727 if(charmed
&& charmed
->isAttackingPlayer())
4730 for (int8 i
= 0; i
< 4; i
++)
4734 Creature
*totem
= ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot
[i
]);
4735 if(totem
&& totem
->isAttackingPlayer())
4743 void Unit::RemoveAllAttackers()
4745 while (m_attackers
.size() != 0)
4747 AttackerSet::iterator iter
= m_attackers
.begin();
4748 if(!(*iter
)->AttackStop())
4750 sLog
.outError("WORLD: Unit has an attacker that isnt attacking it!");
4751 m_attackers
.erase(iter
);
4756 void Unit::ModifyAuraState(uint32 flag
, bool apply
)
4760 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
4762 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
4763 if(GetTypeId() == TYPEID_PLAYER
)
4765 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
4766 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
4768 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
4769 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
4770 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
4771 if (spellInfo
->CasterAuraState
== flag
)
4772 CastSpell(this, itr
->first
, true, NULL
);
4779 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
4781 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
4782 Unit::AuraMap
& tAuras
= GetAuras();
4783 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
4785 if ((*itr
).second
->GetSpellProto()->CasterAuraState
== flag
)
4794 Unit
*Unit::GetOwner() const
4796 uint64 ownerid
= GetOwnerGUID();
4799 return ObjectAccessor::Instance().GetUnit(*this, ownerid
);
4802 Unit
*Unit::GetCharmer() const
4804 uint64 charmerid
= GetCharmerGUID();
4807 return ObjectAccessor::Instance().GetUnit(*this, charmerid
);
4810 Pet
* Unit::GetPet() const
4812 uint64 pet_guid
= GetPetGUID();
4815 Pet
* pet
= ObjectAccessor::Instance().GetPet(pet_guid
);
4818 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
4819 const_cast<Unit
*>(this)->SetPet(0);
4828 Unit
* Unit::GetCharm() const
4830 uint64 charm_guid
= GetCharmGUID();
4833 Unit
* pet
= ObjectAccessor::Instance().GetUnit(*this, charm_guid
);
4836 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
4837 const_cast<Unit
*>(this)->SetCharm(0);
4845 void Unit::SetPet(Pet
* pet
)
4847 SetUInt64Value(UNIT_FIELD_SUMMON
,pet
? pet
->GetGUID() : 0);
4851 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
4853 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
4858 void Unit::SetCharm(Unit
* charmed
)
4860 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
4863 void Unit::UnsummonAllTotems()
4865 for (int8 i
= 0; i
< 4; ++i
)
4870 Creature
*OldTotem
= ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot
[i
]);
4871 if (OldTotem
&& OldTotem
->isTotem())
4872 ((Totem
*)OldTotem
)->UnSummon();
4876 void Unit::SendHealSpellOnPlayer(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
4879 WorldPacket
data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE
, (8+8+4+4+1));
4880 data
.append(pVictim
->GetPackGUID());
4881 data
.append(GetPackGUID());
4884 data
<< uint8(critical
? 1 : 0);
4885 SendMessageToSet(&data
, true);
4888 void Unit::SendHealSpellOnPlayerPet(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
,Powers powertype
, bool critical
)
4890 WorldPacket
data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE
, (8+8+4+4+4+1));
4891 data
.append(pVictim
->GetPackGUID());
4892 data
.append(GetPackGUID());
4894 data
<< uint32(powertype
);
4896 data
<< uint8(critical
? 1 : 0);
4897 SendMessageToSet(&data
, true);
4900 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
4902 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
4905 if(pVictim
->IsImmunedToSpellDamage(spellProto
))
4908 uint32 creatureTypeMask
= GetCreatureTypeMask();
4911 uint32 CastingTime
= GetCastTime(sCastTimesStore
.LookupEntry(spellProto
->CastingTimeIndex
));
4912 if (CastingTime
> 7000) CastingTime
= 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds )
4913 if (CastingTime
< 1500) CastingTime
= 1500;
4915 // Taken/Done fixed damage bonus auras
4916 int32 DoneAdvertisedBenefit
= 0;
4917 int32 TakenAdvertisedBenefit
= 0;
4919 // ..done (for creature type by mask) in taken
4920 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
4921 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
4922 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
4923 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4926 AuraList
const& mDamageDone
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
4927 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
4928 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 &&
4929 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
4930 // -1 == any item class (not wand then)
4931 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
4932 // 0 == any inventory type (not wand then)
4933 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4935 if (GetTypeId() == TYPEID_PLAYER
)
4937 // Damage bonus of spirit
4938 AuraList
const& mDamageDonebySpi
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_SPIRIT
);
4939 for(AuraList::const_iterator i
= mDamageDonebySpi
.begin();i
!= mDamageDonebySpi
.end(); ++i
)
4940 if((*i
)->GetModifier()->m_miscvalue
& 1 << spellProto
->School
)
4941 DoneAdvertisedBenefit
+= int32(GetStat(STAT_SPIRIT
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
4943 // ... and intellect
4944 AuraList
const& mDamageDonebyInt
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT
);
4945 for(AuraList::const_iterator i
= mDamageDonebyInt
.begin();i
!= mDamageDonebyInt
.end(); ++i
)
4946 if ((*i
)->GetModifier()->m_miscvalue
& 1 << spellProto
->School
)
4947 DoneAdvertisedBenefit
+= int32(GetStat(STAT_INTELLECT
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
4951 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
4952 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
4953 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
4954 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4956 // Damage over Time spells bonus calculation
4957 float DotFactor
= 1.0f
;
4958 if(damagetype
== DOT
)
4961 uint32 DotDuration
= GetDuration(spellProto
);
4965 if(DotDuration
> 30000) DotDuration
= 30000;
4966 DotFactor
= DotDuration
/ 15000.0f
;
4968 for(int j
= 0; j
< 3; j
++)
4969 if(spellProto
->Effect
[j
] == 6) x
= j
;
4971 if(spellProto
->EffectAmplitude
[x
] != 0)
4972 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
4975 DoneAdvertisedBenefit
/= DotTicks
;
4976 TakenAdvertisedBenefit
/= DotTicks
;
4981 // Taken/Done total percent damage auras
4982 float DoneTotalMod
= 1.0f
;
4983 float TakenTotalMod
= 1.0f
;
4986 AuraList
const& mModDamagePercentDone
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
4987 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
4988 if( spellProto
->School
!= 0 && ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 &&
4989 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
4990 // -1 == any item class (not wand then)
4991 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
4992 // 0 == any inventory type (not wand then)
4993 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
4996 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
4997 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
4998 if( spellProto
->School
!= 0 && ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 )
4999 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5003 if(spellProto
->SpellVisual
== 1225 && spellProto
->SpellIconID
== 208)
5005 CastingTime
= 2800; // 80% from +shadow damage
5006 DoneTotalMod
= 1.0f
;
5007 TakenTotalMod
= 1.0f
;
5010 if(spellProto
->SpellVisual
== 827 && spellProto
->SpellIconID
== 154 && GetPet())
5012 CastingTime
= 3360; // 96% from +shadow damage
5013 DoneTotalMod
= 1.0f
;
5014 TakenTotalMod
= 1.0f
;
5017 if(spellProto
->Id
== 30455)
5019 CastingTime
/= 3.0f
; // applied 1/3 bonuses in case generic target
5020 if(pVictim
->isFrozen()) // and compensate this for frozen target.
5021 TakenTotalMod
*= 3.0f
;
5025 float LvlPenalty
= 0.0f
;
5026 if(spellProto
->spellLevel
< 20)
5027 LvlPenalty
= (20.0f
- (float)(spellProto
->spellLevel
)) * 3.75f
;
5028 float LvlFactor
= ((float)(spellProto
->spellLevel
) + 6.0f
) / (float)(getLevel());
5029 if(LvlFactor
> 1.0f
)
5032 // Spellmod SpellDamage
5033 float SpellModSpellDamage
= 100.0f
;
5034 if (GetTypeId() == TYPEID_PLAYER
)
5035 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_DAMAGE
,SpellModSpellDamage
);
5036 SpellModSpellDamage
/= 100.0f
;
5038 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
* SpellModSpellDamage
/ 100.0f
;
5039 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
/ 100.0f
;
5041 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
5042 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
5044 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
5047 bool Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, int32
*peffect
, Unit
*pVictim
)
5049 // Chance to crit is computed from INT and LEVEL as follows:
5050 // chance = base + INT / (rate0 + rate1 * LEVEL)
5051 // The formula keeps the crit chance at %5 on every level unless the player
5052 // increases his intelligence by other means (enchants, buffs, talents, ...)
5053 if(spellProto
->Id
== 15290 || spellProto
->Id
== 39373) return false;
5055 float crit_chance
= 0.0f
;
5058 if (GetTypeId() != TYPEID_PLAYER
)
5061 // TODO: can creatures have critical chance auras?
5062 crit_chance
= m_baseSpellCritChance
;
5063 AuraList
const& mSpellCritSchool
= GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
);
5064 for(AuraList::const_iterator i
= mSpellCritSchool
.begin(); i
!= mSpellCritSchool
.end(); ++i
)
5065 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
5066 crit_chance
+= (*i
)->GetModifier()->m_amount
;
5069 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ spellProto
->School
);
5072 // only players use intelligence for critical chance computations
5073 if (GetTypeId() == TYPEID_PLAYER
)
5075 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
5082 AuraList
const& mAttackerSpellCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
);
5083 for(AuraList::const_iterator i
= mAttackerSpellCrit
.begin(); i
!= mAttackerSpellCrit
.end(); ++i
)
5084 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
5085 crit_chance
+= (*i
)->GetModifier()->m_amount
;
5087 // flat: Resilience - reduce crit chance by x%
5088 crit_chance
-= pVictim
->m_modResilience
;
5090 // flat: scripted (increase crit chance ... against ... target by x%
5091 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
5092 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
5094 switch((*i
)->GetModifier()->m_miscvalue
)
5097 case 849: if(pVictim
->isFrozen()) crit_chance
+= 10; break;
5099 case 910: if(pVictim
->isFrozen()) crit_chance
+= 20; break;
5101 case 911: if(pVictim
->isFrozen()) crit_chance
+= 30; break;
5103 case 912: if(pVictim
->isFrozen()) crit_chance
+= 40; break;
5105 case 913: if(pVictim
->isFrozen()) crit_chance
+= 50; break;
5110 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
5111 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
5112 crit_chance
+= (*i
)->GetModifier()->m_amount
;
5115 crit_chance
= crit_chance
> 0.0 ? crit_chance
: 0.0;
5116 if (roll_chance_f(crit_chance
))
5118 int32 crit_bonus
= *peffect
/ 2;
5119 if (GetTypeId() == TYPEID_PLAYER
) // adds additional damage to crit_bonus (from talents)
5120 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
5122 *peffect
+= crit_bonus
;
5123 // Resilience - reduce crit damage by 2x%
5125 *peffect
-= int32(pVictim
->m_modResilience
* 2/100 * (*peffect
));
5132 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
5136 // Vampiric Embrace, Shadowmend - cannot critically heal
5137 if(spellProto
->Id
== 15290 || spellProto
->Id
== 39373) return healamount
;
5139 int32 AdvertisedBenefit
= 0;
5140 uint32 CastingTime
= GetCastTime(sCastTimesStore
.LookupEntry(spellProto
->CastingTimeIndex
));
5141 if (CastingTime
> 7000) CastingTime
= 7000;
5142 if (CastingTime
< 1500) CastingTime
= 1500;
5143 if (spellProto
->Effect
[0] == SPELL_EFFECT_APPLY_AURA
) CastingTime
= 3500;
5145 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
5146 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
5147 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
5148 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
5150 // Healing bonus of spirit, intellect and strength
5151 if (GetTypeId() == TYPEID_PLAYER
)
5153 AdvertisedBenefit
+= int32(GetStat(STAT_SPIRIT
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_SPIRIT
) / 100.0f
);
5154 AdvertisedBenefit
+= int32(GetStat(STAT_INTELLECT
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT
) / 100.0f
);
5155 AdvertisedBenefit
+= int32(GetStat(STAT_STRENGTH
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_STRENGTH
) / 100.0f
);
5159 AdvertisedBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_HEALING
);
5162 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0xC0000000))
5164 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
5165 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
5166 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
5168 if ((spellProto
->SpellFamilyFlags
& 0x40000000) && (*i
)->GetEffIndex() == 1)
5169 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
5171 else if ((spellProto
->SpellFamilyFlags
& 0x80000000) && (*i
)->GetEffIndex() == 0)
5172 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
5175 // Healing over Time spells
5176 float DotFactor
= 1.0f
;
5177 if(damagetype
== DOT
)
5180 uint32 DotDuration
= GetDuration(spellProto
);
5182 if(DotDuration
> 30000) DotDuration
= 30000;
5183 DotFactor
= DotDuration
/ 15000.0f
;
5185 for(int j
= 0; j
< 3; j
++)
5186 if(spellProto
->Effect
[j
] == 6) x
= j
;
5188 if(spellProto
->EffectAmplitude
[x
] != 0)
5189 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
5191 AdvertisedBenefit
/= DotTicks
;
5195 float LvlPenalty
= 0.0f
;
5196 if(spellProto
->spellLevel
< 20)
5197 LvlPenalty
= (20.0f
- (float)(spellProto
->spellLevel
)) * 3.75f
;
5198 float LvlFactor
= ((float)(spellProto
->spellLevel
) + 6.0f
) / (float)(getLevel());
5199 if(LvlFactor
> 1.0f
)
5202 float ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
/ 100.0f
;
5204 // use float as more appropriate for negative values and percent applying
5205 float heal
= healamount
+ ActualBenefit
;
5207 // TODO: check for ALL/SPELLS type
5208 // Healing done percent
5209 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
5210 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
5211 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
5213 // Healing taken percent
5214 AuraList
const& mHealingPct
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING_PCT
);
5215 for(AuraList::const_iterator i
= mHealingPct
.begin();i
!= mHealingPct
.end(); ++i
)
5216 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
5218 if (heal
< 0) heal
= 0;
5220 return uint32(heal
);
5223 bool Unit::IsImmunedToPhysicalDamage() const
5225 //If m_immuneToDamage type contain magic, IMMUNE damage.
5226 SpellImmuneList
const& damageImmList
= m_spellImmune
[IMMUNITY_DAMAGE
];
5227 for (SpellImmuneList::const_iterator itr
= damageImmList
.begin(); itr
!= damageImmList
.end(); ++itr
)
5228 if(itr
->type
& IMMUNE_DAMAGE_PHYSICAL
)
5231 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5232 SpellImmuneList
const& spellImmList
= m_spellImmune
[IMMUNITY_SCHOOL
];
5233 for (SpellImmuneList::const_iterator itr
= spellImmList
.begin(); itr
!= spellImmList
.end(); ++itr
)
5234 if(itr
->type
& IMMUNE_SCHOOL_PHYSICAL
)
5240 bool Unit::IsImmunedToSpellDamage(SpellEntry
const* spellInfo
) const
5242 //If m_immuneToDamage type contain magic, IMMUNE damage.
5243 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
5244 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
5245 if(itr
->type
& uint32(1<<spellInfo
->School
))
5248 //If m_immuneToSchool type contain this school type, IMMUNE damage.
5249 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
5250 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
5251 if(itr
->type
& uint32(1<<spellInfo
->School
))
5257 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
) const
5262 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
5263 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
5264 if(itr
->type
== spellInfo
->Dispel
)
5267 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
5268 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
5269 if(itr
->type
== spellInfo
->Mechanic
)
5273 AuraList
const& mModMechanicRes
= GetAurasByType(SPELL_AURA_MOD_MECHANIC_RESISTANCE
);
5274 for(AuraList::const_iterator i
= mModMechanicRes
.begin();i
!= mModMechanicRes
.end(); ++i
)
5275 if((*i
)->GetModifier()->m_miscvalue
== int32(spellInfo
->Mechanic
))
5276 chance
+= (*i
)->GetModifier()->m_amount
;
5277 if(roll_chance_i(chance
))
5283 bool Unit::IsImmunedToSpellEffect(uint32 effect
) const
5285 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
5286 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
5287 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
5288 if(itr
->type
== effect
)
5294 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
5299 uint32 family
= spellInfo
->SpellFamilyName
;
5300 uint32 flags
= spellInfo
->SpellFamilyFlags
;
5302 if((family
== 5 && flags
== 256) || //Searing Pain
5303 (family
== 6 && flags
== 8192) || //Mind Blast
5304 (family
== 11 && flags
== 1048576)) //Earth Shock
5310 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
)
5312 if(!pVictim
) return;
5317 uint32 creatureTypeMask
= GetCreatureTypeMask();
5319 if(GetTypeId() != TYPEID_PLAYER
&& ((Creature
*)this)->isPet())
5321 if(getPowerType() == POWER_FOCUS
)
5323 uint32 happiness
= GetPower(POWER_HAPPINESS
);
5324 if(happiness
>=666000)
5325 *pdamage
= uint32(*pdamage
* 1.25);
5326 else if(happiness
<333000)
5327 *pdamage
= uint32(*pdamage
* 0.75);
5328 else *pdamage
= uint32(*pdamage
* 1.0);
5332 // Taken/Done fixed damage bonus auras
5333 int32 DoneFlatBenefit
= 0;
5334 int32 TakenFlatBenefit
= 0;
5336 // ..done (for creature type by mask) in taken
5337 AuraList
const& mDamageDoneCreature
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
5338 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
5339 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
5340 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5343 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
5345 // ..done (base at attack power and creature type)
5346 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER
);
5347 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
5348 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
5349 DoneFlatBenefit
+= int32((*i
)->GetModifier()->m_amount
/14.0f
* GetAttackTime(attType
)/1000);
5351 // ..done (base at attack power for marked target)
5352 if(attType
== RANGED_ATTACK
)
5354 AuraList
const& mRangedAttackPowerAttackerBonus
= pVictim
->GetAurasByType(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
5355 for(AuraList::const_iterator i
= mRangedAttackPowerAttackerBonus
.begin();i
!= mRangedAttackPowerAttackerBonus
.end(); ++i
)
5356 DoneFlatBenefit
+= int32((*i
)->GetModifier()->m_amount
/14.0f
* GetAttackTime(RANGED_ATTACK
)/1000);
5360 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
5361 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
5362 if((*i
)->GetModifier()->m_miscvalue
& IMMUNE_SCHOOL_PHYSICAL
)
5363 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5365 if(attType
!=RANGED_ATTACK
)
5367 AuraList
const& mModMeleeDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
5368 for(AuraList::const_iterator i
= mModMeleeDamageTaken
.begin(); i
!= mModMeleeDamageTaken
.end(); ++i
)
5369 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5373 AuraList
const& mModRangedDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
5374 for(AuraList::const_iterator i
= mModRangedDamageTaken
.begin(); i
!= mModRangedDamageTaken
.end(); ++i
)
5375 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5378 // Done/Taken total percent damage auras
5379 float TakenTotalMod
= 1;
5382 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
5383 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
5386 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
5387 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
5388 if((*i
)->GetModifier()->m_miscvalue
& IMMUNE_SCHOOL_PHYSICAL
)
5389 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5391 if(attType
!= RANGED_ATTACK
)
5393 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
5394 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
5395 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5399 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
5400 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
5401 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5404 float tmpDamage
= ((int32(*pdamage
) + DoneFlatBenefit
) + TakenFlatBenefit
)*TakenTotalMod
;
5406 // bonus result can be negative
5407 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
5410 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
5414 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
5417 if(itr
->type
== type
)
5419 m_spellImmune
[op
].erase(itr
);
5420 next
= m_spellImmune
[op
].begin();
5424 Immune
.spellId
= spellId
;
5426 m_spellImmune
[op
].push_back(Immune
);
5430 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
5432 if(itr
->spellId
== spellId
)
5434 m_spellImmune
[op
].erase(itr
);
5442 float Unit::GetWeaponProcChance() const
5444 // normalized proc chance for weapon attack speed
5445 // (odd formulae...)
5446 if(isAttackReady(BASE_ATTACK
))
5447 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
5448 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
5449 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
5453 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
5455 // proc per minute chance calculation
5456 if (PPM
<= 0) return 0.0f
;
5457 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
5461 void Unit::Mount(uint32 mount
, bool taxi
)
5466 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
5468 uint32 flag
= UNIT_FLAG_MOUNT
;
5470 flag
|= UNIT_FLAG_DISABLE_MOVE
;
5472 SetFlag( UNIT_FIELD_FLAGS
, flag
);
5475 if(GetTypeId() == TYPEID_PLAYER
)
5477 Pet
* pet
= GetPet();
5480 if(pet
->getPetType() == SUMMON_PET
|| pet
->getPetType() == HUNTER_PET
)
5482 ((Player
*)this)->SetOldPetNumber(pet
->GetCharmInfo()->GetPetNumber());
5483 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
5486 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
5489 ((Player
*)this)->SetOldPetNumber(0);
5493 void Unit::Unmount()
5498 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
5499 RemoveFlag( UNIT_FIELD_FLAGS
,UNIT_FLAG_DISABLE_MOVE
| UNIT_FLAG_MOUNT
);
5501 if(GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->GetOldPetNumber() && isAlive())
5503 Pet
* NewPet
= new Pet(this);
5504 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetOldPetNumber(), true))
5507 ((Player
*)this)->SetOldPetNumber(0);
5511 void Unit::SetInCombat()
5513 m_CombatTimer
= 5000;
5514 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
5516 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
5517 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
5520 void Unit::ClearInCombat(bool force
)
5522 // wait aura and combat timer expire
5523 if(!force
&& HasAuraType(SPELL_AURA_INTERRUPT_REGEN
))
5527 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
5529 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
5530 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
5532 // remove combo points
5533 if(GetTypeId()==TYPEID_PLAYER
)
5534 ((Player
*)this)->ClearComboPoints();
5537 bool Unit::isTargetableForAttack()
5539 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
5541 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
5544 int32
Unit::ModifyHealth(int32 dVal
)
5551 int32 curHealth
= (int32
)GetHealth();
5553 int32 val
= dVal
+ curHealth
;
5560 int32 maxHealth
= (int32
)GetMaxHealth();
5565 gain
= val
- curHealth
;
5567 else if(curHealth
!= maxHealth
)
5569 SetHealth(maxHealth
);
5570 gain
= maxHealth
- curHealth
;
5576 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
5583 int32 curPower
= (int32
)GetPower(power
);
5585 int32 val
= dVal
+ curPower
;
5592 int32 maxPower
= (int32
)GetMaxPower(power
);
5596 SetPower(power
,val
);
5597 gain
= val
- curPower
;
5599 else if(curPower
!= maxPower
)
5601 SetPower(power
,maxPower
);
5602 gain
= maxPower
- curPower
;
5608 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
5613 // Always can see self
5617 // player visible for other player if not logout and at same transport
5618 // including case when player is out of world
5619 bool at_same_transport
=
5620 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
5621 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
5622 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
5623 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
5626 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
5629 // always seen by owner
5630 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
5633 // Grid dead/alive checks
5634 if( u
->GetTypeId()==TYPEID_PLAYER
)
5636 // non visible at grid for any stealth state
5637 if(!IsVisibleInGridForPlayer((Player
*)u
))
5640 // if player is dead then he can't detect anyone in anycases
5646 // all dead creatures/players not visible for any creatures
5647 if(!u
->isAlive() || !isAlive())
5651 // different visible distance checks
5652 if(u
->isInFlight()) // what see player in flight
5654 // use object grey distance for all (only see objects any way)
5655 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
5658 else if(!isAlive()) // distance for show body
5660 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
5663 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
5665 if(u
->GetTypeId()==TYPEID_PLAYER
)
5667 // Players far than max visible distance for player or not in our map are not visible too
5668 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5673 // Units far than max visible distance for creature or not in our map are not visible too
5674 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5678 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
5680 // Pet/charmed far than max visible distance for player or not in our map are not visible too
5681 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5684 else // distance for show creature
5686 // Units far than max visible distance for creature or not in our map are not visible too
5687 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5691 // Visible units, always are visible for all units, except for units under invisibility
5692 if (m_Visibility
== VISIBILITY_ON
&& u
->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY
)
5695 // GMs are visible for higher gms (or players are visible for gms)
5696 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
5697 return (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity());
5699 // non faction visibility non-breakable for non-GMs
5700 if (m_Visibility
== VISIBILITY_OFF
)
5703 // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility
5704 if (m_Visibility
== VISIBILITY_GROUP_INVISIBILITY
)
5706 if(u
->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY
|| m_invisibilityvalue
<= u
->m_detectInvisibility
)
5710 // Units that can detect invisibility always are visible for units that can be detected
5711 if (u
->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY
)
5713 if(m_detectInvisibility
>= u
->m_invisibilityvalue
)
5717 // Stealth/invisible not hostile units, not visible (except Player-with-Player case)
5718 if (!u
->IsHostileTo(this))
5720 // 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)
5721 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
5723 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
5726 // else apply same rules as for hostile case (detecting check)
5731 // Hunter mark functionality
5732 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
5733 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
5734 if((*iter
)->GetCasterGUID()==u
->GetGUID())
5738 // unit got in stealth in this moment and must ignore old detected state
5739 // invisibility not have chance for detection
5740 if (m_Visibility
== VISIBILITY_ON
|| m_Visibility
== VISIBILITY_GROUP_NO_DETECT
|| m_Visibility
== VISIBILITY_GROUP_INVISIBILITY
)
5743 // NOW ONLY STEALTH CASE
5745 // stealth and detected
5746 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->HaveAtClient(this) )
5749 //if in non-detect mode then invisible for unit
5754 bool IsVisible
= true;
5755 bool isInFront
= u
->isInFront(this,World::GetMaxVisibleDistanceForObject());
5756 float distance
= sqrt(GetDistanceSq(u
));
5758 // If is attacked then stealth is lost, some creature can use stealth too
5759 if (this->isAttacked())
5762 // If there is collision rogue is seen regardless of level difference
5763 // TODO: check sizes in DB
5764 if (distance
< 0.24f
)
5767 //If a mob or player is stunned he will not be able to detect stealth
5768 if ((u
->hasUnitState(UNIT_STAT_STUNDED
)) && (u
!= this))
5774 // Cases based on level difference and position
5775 int32 levelDiff
= u
->getLevel() - this->getLevel();
5777 //If mob is 5 levels more than player he gets detected automaticly
5778 if (u
->GetTypeId()!=TYPEID_PLAYER
&& levelDiff
> 5)
5781 // If victim has more than 5 lvls above caster
5782 if ((this->GetTypeId() == TYPEID_UNIT
)&& ( levelDiff
> 5 ))
5785 // If caster has more than 5 levels above victim
5786 if ((this->GetTypeId() == TYPEID_UNIT
)&& ( levelDiff
< -5 ))
5792 float modifier
= 1; // 100 pct
5793 float pvpMultiplier
= 0;
5794 float distanceFormula
= 0;
5796 //This allows to check talent tree and will add addition stealth dependant on used points)
5797 uint32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
5798 //****************************************************************************************
5799 // Stealth detection calculation
5800 int32 x
= (((u
->m_detectStealth
+1) / 5) - (((m_stealthvalue
+1) / 5) + (stealthMod
/5) + 59));
5803 // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp
5804 if (u
->GetTypeId() != TYPEID_PLAYER
)
5805 rank
= ((Creature
const*)u
)->GetCreatureInfo()->rank
;
5807 // Probabilty of being seen
5809 distanceFormula
= ((sWorld
.getRate(RATE_CREATURE_AGGRO
) * 16) / (abs(levelDiff
) + 1.5)) * 2;
5811 distanceFormula
= (((sWorld
.getRate(RATE_CREATURE_AGGRO
) * 16)) / 2) * (levelDiff
+ 1);
5813 // Original probability values
5814 // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference
5815 //at this distance, the detector has to be a 15% prob of detect
5816 float averageDist
= 1 - 0.11016949 * x
+ 0.00301637 * x
* x
;
5817 if (averageDist
< 1) averageDist
= 1;
5820 if (distance
> averageDist
)
5821 //prob between 10% and 0%
5822 prob
= (averageDist
- 200 + 9 * distance
) / (averageDist
- 20);
5824 prob
= 75 - (60 / averageDist
) * distance
; //prob between 15% and 75% (75% max prob)
5826 // If is not in front, probability floor
5832 // Mob rank affects modifier
5833 modifier
= rank
<= 4 ? 1 + rank
* 0.2f
: 1;
5835 if (distance
< 0.24f
)
5840 // PVP distance assigned depending on level
5841 if (this->GetTypeId() == TYPEID_UNIT
)
5843 // Level diff floor/ceiling <-5,5>
5844 pvpMultiplier
= levelDiff
> 5 ? 12 : levelDiff
< 5 ? 2 : 7 + levelDiff
;
5845 pvpMultiplier
= pvpMultiplier
- (x
/ 100);
5848 // PVP stealth handler
5849 if (this->GetTypeId() == TYPEID_PLAYER
)
5851 // Do not loose stealth when coming from back
5858 // If comes in front
5859 if (isInFront
&& (distance
>= pvpMultiplier
))
5865 if (isInFront
&& (distance
< pvpMultiplier
))
5872 // PVE stealth handler
5873 // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled
5874 // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you
5875 if ((distance
< 100) && (distance
> ((distanceFormula
* 2) * modifier
)) && (distance
> 0.24f
))
5881 //If victim is level lower or more probability of detection drops
5882 if ((levelDiff
< 0) && (distance
> 0.24f
))
5884 if (abs(levelDiff
) > 4)
5888 if (rand_chance() > ( prob
* modifier
/ (30 + levelDiff
* 5)))
5893 // Level detection based on level, the higher the mob level the higher the chance of detection.
5894 if ((distance
> 0.24f
) && (levelDiff
< 5) && (levelDiff
>= 0))
5896 if (rand_chance() > ((prob
* modifier
) / (30 - levelDiff
* 5) ))
5905 // Didn't match any criteria ?
5906 DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance
,levelDiff
,u
->GetTypeId(),prob
, modifier
);
5912 void Unit::SetVisibility(UnitVisibility x
)
5918 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
5920 if(GetTypeId()==TYPEID_PLAYER
)
5921 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5923 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5927 float Unit::GetSpeed( UnitMoveType mtype
) const
5929 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
5932 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
5934 m_speed_rate
[mtype
] = 1.0f
;
5935 ApplySpeedMod(mtype
, rate
, forced
, true);
5938 void Unit::ApplySpeedMod(UnitMoveType mtype
, float rate
, bool forced
, bool apply
)
5943 m_speed_rate
[mtype
] *= rate
;
5945 m_speed_rate
[mtype
] /= rate
;
5950 if(forced
) { data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16); }
5951 else { data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 16); }
5954 if(forced
) { data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 16); }
5955 else { data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 16); }
5958 if(forced
) { data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16); }
5959 else { data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 16); }
5962 if(forced
) { data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16); }
5963 else { data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 16); }
5966 if(forced
) { data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16); }
5967 else { data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 16); }
5970 if(forced
) { data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16); }
5971 else { data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 16); }
5974 if(forced
) { data
.Initialize(SMSG_FORCE_FLY_SPEED_CHANGE
, 16); }
5975 else { data
.Initialize(SMSG_MOVE_SET_FLY_SPEED
, 16); }
5980 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
5984 data
.append(GetPackGUID());
5986 if (mtype
== MOVE_RUN
) data
<< uint8(0); // new 2.1.0
5987 data
<< float(GetSpeed(mtype
));
5988 SendMessageToSet( &data
, true );
5990 if(Pet
* pet
= GetPet())
5991 pet
->SetSpeed(mtype
,m_speed_rate
[mtype
],forced
);
5994 void Unit::SetHover(bool on
)
5997 CastSpell(this,11010,true);
5999 RemoveAurasDueToSpell(11010);
6002 void Unit::setDeathState(DeathState s
)
6008 if(IsNonMeleeSpellCasted(false))
6009 InterruptNonMeleeSpells(false);
6014 RemoveAllAurasOnDeath();
6015 UnsummonAllTotems();
6017 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
6019 //_ApplyAllAuraMods();
6024 /*########################################
6026 ######## AGGRO SYSTEM ########
6028 ########################################*/
6029 bool Unit::CanHaveThreatList() const
6031 if(GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() && !((Creature
*)this)->isTotem() )
6037 //======================================================================
6039 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchools school
)
6041 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
6044 if(school
>= MAX_SPELL_SCHOOL
)
6046 sLog
.outError("Unit::ApplyTotalThreatModifier: Spell school with out-of-range value: %u",uint32(school
));
6050 return threat
* m_threatModifier
[school
];
6053 //======================================================================
6055 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchools school
, SpellEntry
const *threatSpell
)
6057 // Only mobs can manage threat lists
6058 if(CanHaveThreatList())
6059 m_ThreatManager
.addThreat(pVictim
, threat
, school
, threatSpell
);
6062 //======================================================================
6064 void Unit::DeleteThreatList()
6066 m_ThreatManager
.clearReferences();
6069 //======================================================================
6071 void Unit::TauntApply(Unit
* taunter
)
6073 assert(GetTypeId()== TYPEID_UNIT
);
6075 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
6078 if(!CanHaveThreatList())
6081 Unit
*target
= getVictim();
6082 if(target
&& target
== taunter
)
6085 SetInFront(taunter
);
6086 if (((Creature
*)this)->AI())
6087 ((Creature
*)this)->AI()->AttackStart(taunter
);
6089 m_ThreatManager
.tauntApply(taunter
);
6092 //======================================================================
6094 void Unit::TauntFadeOut(Unit
*taunter
)
6096 assert(GetTypeId()== TYPEID_UNIT
);
6098 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
6101 if(!CanHaveThreatList())
6104 Unit
*target
= getVictim();
6105 if(!target
|| target
!= taunter
)
6108 if(m_ThreatManager
.isThreatListEmpty())
6110 if(((Creature
*)this)->AI())
6111 ((Creature
*)this)->AI()->EnterEvadeMode();
6115 m_ThreatManager
.tauntFadeOut(taunter
);
6116 target
= m_ThreatManager
.getHostilTarget();
6118 if (target
&& target
!= taunter
)
6121 if (((Creature
*)this)->AI())
6122 ((Creature
*)this)->AI()->AttackStart(target
);
6126 //======================================================================
6128 bool Unit::SelectHostilTarget()
6130 //function provides main threat functionality
6131 //next-victim-selection algorithm and evade mode are called
6132 //threat list sorting etc.
6134 assert(GetTypeId()== TYPEID_UNIT
);
6135 Unit
* target
= NULL
;
6137 //This function only useful once AI has been initilazied
6138 if (!((Creature
*)this)->AI())
6141 if(!m_ThreatManager
.isThreatListEmpty())
6143 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
6145 target
= m_ThreatManager
.getHostilTarget();
6152 ((Creature
*)this)->AI()->AttackStart(target
);
6156 if(isInCombat() && !HasAuraType(SPELL_AURA_MOD_TAUNT
) && CanFreeMove() && m_attackers
.empty())
6157 ((Creature
*)this)->AI()->EnterEvadeMode();
6162 //======================================================================
6163 //======================================================================
6164 //======================================================================
6166 void Unit::CalculateSpellDamageAndDuration(int32
* damage
, int32
* duration
, SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
)
6168 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
6170 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
6171 bool needClearCombo
= false;
6178 level
= getLevel() - spellProto
->spellLevel
;
6179 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
6180 level
= spellProto
->maxLevel
;
6182 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
6183 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
6184 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
6185 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
6186 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
6188 value
= basePoints
+ rand32(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
6190 if(int32(spellProto
->EffectBaseDice
[effect_index
]) != randomPoints
&& GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
6191 value
+= ((Pet
*)this)->GetBonusDamage(); //bonus damage only on spells without fixed basePoints?)
6193 if(comboDamage
!= 0 && unitPlayer
&& m_attacking
&& (m_attacking
->GetGUID() == unitPlayer
->GetComboTarget()))
6195 value
+= (int32
)(comboDamage
* comboPoints
);
6198 if( spellProto
->SpellIconID
== 514 && spellProto
->SpellFamilyName
== SPELLFAMILY_ROGUE
)
6199 value
+= (int32
)(GetTotalAttackPowerValue(BASE_ATTACK
) * comboPoints
* 0.03);
6201 needClearCombo
= true;
6204 if (GetTypeId() == TYPEID_PLAYER
)
6206 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
6207 switch(effect_index
)
6210 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
6213 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
6216 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
6220 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, value
);
6229 int32 minduration
= GetDuration(spellProto
);
6230 int32 maxduration
= GetMaxDuration(spellProto
);
6232 if( minduration
!= -1 && minduration
!= maxduration
)
6234 *duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
6235 needClearCombo
= true;
6238 *duration
= minduration
;
6241 if(unitPlayer
&& needClearCombo
)
6242 unitPlayer
->SetComboPoints(unitPlayer
->GetComboTarget(), 0);
6245 void Unit::AddDiminishing(DiminishingMechanics mech
, uint32 hitTime
, uint32 hitCount
)
6247 m_Diminishing
.push_back(DiminishingReturn(mech
,hitTime
,hitCount
));
6250 DiminishingLevels
Unit::GetDiminishing(DiminishingMechanics mech
)
6252 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6254 if(i
->Mechanic
!= mech
) continue;
6255 if(!i
->hitCount
) return DIMINISHING_LEVEL_1
;
6256 if(!i
->hitTime
) return DIMINISHING_LEVEL_1
;
6257 // If last spell was casted more than 15 seconds ago - reset the count.
6258 if((getMSTime() - i
->hitTime
) > 15000)
6260 i
->hitCount
= DIMINISHING_LEVEL_1
;
6261 return DIMINISHING_LEVEL_1
;
6263 // or else increase the count.
6266 if(i
->hitCount
> DIMINISHING_LEVEL_2
)
6268 i
->hitCount
= DIMINISHING_LEVEL_IMMUNE
;
6269 return DIMINISHING_LEVEL_IMMUNE
;
6271 else return DiminishingLevels(i
->hitCount
);
6274 return DIMINISHING_LEVEL_1
;
6277 void Unit::IncrDiminishing(DiminishingMechanics mech
, uint32 duration
)
6279 // Checking for existing in the table
6280 bool IsExist
= false;
6281 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6283 if(i
->Mechanic
!= mech
)
6287 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
6292 case DIMINISHING_LEVEL_2
: i
->hitTime
= uint32(getMSTime() + duration
); break;
6293 case DIMINISHING_LEVEL_3
: i
->hitTime
= uint32(getMSTime() + duration
*0.5); break;
6294 case DIMINISHING_LEVEL_IMMUNE
: i
->hitTime
= uint32(getMSTime() + duration
*0.25); break;
6302 AddDiminishing(mech
,uint32(getMSTime() + duration
),DIMINISHING_LEVEL_2
);
6305 void Unit::UpdateDiminishingTime(DiminishingMechanics mech
)
6307 // Checking for existing in the table
6308 bool IsExist
= false;
6309 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6311 if(i
->Mechanic
!= mech
)
6315 i
->hitTime
= getMSTime();
6320 AddDiminishing(mech
,getMSTime(),DIMINISHING_LEVEL_1
);
6323 DiminishingMechanics
Unit::Mechanic2DiminishingMechanics(uint32 mech
)
6327 case MECHANIC_CHARM
: case MECHANIC_FEAR
: case MECHANIC_SLEEP
:
6328 return DIMINISHING_MECHANIC_CHARM
;
6329 case MECHANIC_CONFUSED
: case MECHANIC_KNOCKOUT
: case MECHANIC_POLYMORPH
:
6330 return DIMINISHING_MECHANIC_CONFUSE
;
6331 case MECHANIC_ROOT
: case MECHANIC_FREEZE
:
6332 return DIMINISHING_MECHANIC_ROOT
;
6333 case MECHANIC_STUNDED
:
6334 return DIMINISHING_MECHANIC_STUN
;
6335 case MECHANIC_CHASE
:
6336 return DIMINISHING_MECHANIC_SPEED
;
6340 return DIMINISHING_NONE
;
6343 float Unit::ApplyDiminishingToDuration(DiminishingMechanics mech
, int32 duration
,Unit
* caster
)
6345 if(duration
== -1 || mech
== DIMINISHING_NONE
)
6348 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
6349 if(duration
> 10000)
6351 // test pet/charm masters instead pets/charmeds
6352 Unit
const* targetOwner
= GetCharmerOrOwner();
6353 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
6355 Unit
const* target
= targetOwner
? targetOwner
: this;
6356 Unit
const* source
= casterOwner
? casterOwner
: caster
;
6358 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
6364 // Stun diminishing is applies to mobs too
6365 if(mech
== DIMINISHING_MECHANIC_STUN
|| GetTypeId() == TYPEID_PLAYER
)
6367 DiminishingLevels diminish
= GetDiminishing(mech
);
6370 case DIMINISHING_LEVEL_1
: IncrDiminishing(mech
, duration
); break;
6371 case DIMINISHING_LEVEL_2
: IncrDiminishing(mech
, duration
); mod
= 0.5f
; break;
6372 case DIMINISHING_LEVEL_3
: IncrDiminishing(mech
, duration
); mod
= 0.25f
; break;
6373 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
; break;
6381 Creature
* Unit::SummonCreature(uint32 id
, float x
, float y
, float z
, float ang
,TempSummonType spwtype
,uint32 despwtime
)
6383 TemporarySummon
* pCreature
= new TemporarySummon(this,this);
6385 pCreature
->SetInstanceId(GetInstanceId());
6387 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), GetMapId(), x
, y
, z
, ang
, id
))
6393 pCreature
->Summon(spwtype
, despwtime
);
6395 //return the creature therewith the summoner has access to it
6399 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
6401 return ObjectAccessor::Instance().GetUnit(object
,guid
);
6404 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
6406 return isVisibleForOrDetect(u
,false,inVisibleList
);
6409 uint32
Unit::GetCreatureType() const
6411 if(GetTypeId() == TYPEID_PLAYER
)
6413 switch(((Player
const*)this)->m_form
)
6420 case FORM_GHOSTWOLF
:
6421 case FORM_SWIFT_FLIGHT
:
6423 return CREATURE_TYPE_BEAST
;
6425 case FORM_SPIRITOFREDEMPTION
:
6426 return CREATURE_TYPE_ELEMENTAL
;
6429 return CREATURE_TYPE_HUMANOID
;
6433 return ((Creature
*)this)->GetCreatureInfo()->type
;
6436 /*#######################################
6438 ######## STAT SYSTEM ########
6440 #######################################*/
6442 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
6444 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
6446 sLog
.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
6452 switch(modifierType
)
6456 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
6460 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
6463 val
= (100.0f
+ amount
) / 100.0f
;
6464 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
6471 if(!CanModifyStats())
6476 case UNIT_MOD_STAT_STRENGTH
:
6477 case UNIT_MOD_STAT_AGILITY
:
6478 case UNIT_MOD_STAT_STAMINA
:
6479 case UNIT_MOD_STAT_INTELLECT
:
6480 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
6482 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
6483 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
6487 case UNIT_MOD_FOCUS
:
6488 case UNIT_MOD_ENERGY
:
6489 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
6491 case UNIT_MOD_RESISTANCE_HOLY
:
6492 case UNIT_MOD_RESISTANCE_FIRE
:
6493 case UNIT_MOD_RESISTANCE_NATURE
:
6494 case UNIT_MOD_RESISTANCE_FROST
:
6495 case UNIT_MOD_RESISTANCE_SHADOW
:
6496 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
6498 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
6499 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
6501 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
6502 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
6503 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
6512 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
6514 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
6516 sLog
.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
6520 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
6523 return m_auraModifiersGroup
[unitMod
][modifierType
];
6526 float Unit::GetTotalStatValue(Stats stat
) const
6528 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
6530 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
6533 // value = ((base_value * base_pct) + total_value) * total_pct
6534 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
6535 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
6536 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
6537 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
6542 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
6544 if(unitMod
>= UNIT_MOD_END
)
6546 sLog
.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
6550 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
6553 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
6554 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
6555 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
6556 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
6561 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
6563 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
6567 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
6568 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
6569 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
6570 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
6571 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
6572 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
6581 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
6583 Stats stat
= STAT_STRENGTH
;
6587 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
6588 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
6589 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
6590 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
6591 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
6600 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
6602 Powers power
= POWER_MANA
;
6606 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
6607 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
6608 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
6609 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
6610 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
6619 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
6621 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
6623 float val
= GetTotalAuraModValue(unitMod
);
6630 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
6632 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
6635 return m_weaponDamage
[attType
][type
];
6638 void Unit::SetLevel(uint32 lvl
)
6640 SetUInt32Value(UNIT_FIELD_LEVEL
,lvl
);
6643 if (GetTypeId() == TYPEID_PLAYER
)
6644 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
6647 void Unit::SetHealth(uint32 val
)
6649 uint32 maxHealth
= GetMaxHealth();
6653 SetUInt32Value(UNIT_FIELD_HEALTH
,val
);
6656 if (GetTypeId() == TYPEID_PLAYER
)
6657 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
6660 void Unit::SetMaxHealth(uint32 val
)
6662 uint32 health
= GetHealth();
6663 SetUInt32Value(UNIT_FIELD_MAXHEALTH
,val
);
6666 if (GetTypeId() == TYPEID_PLAYER
)
6667 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
6673 void Unit::SetPower(Powers power
, uint32 val
)
6675 uint32 maxPower
= GetMaxPower(power
);
6679 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
,val
);
6682 if (GetTypeId() == TYPEID_PLAYER
)
6683 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
6686 void Unit::SetMaxPower(Powers power
, uint32 val
)
6688 uint32 cur_power
= GetPower(power
);
6689 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
,val
);
6692 if (GetTypeId() == TYPEID_PLAYER
)
6693 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
6696 SetPower(power
, val
);
6699 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
6701 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
6704 if (GetTypeId() == TYPEID_PLAYER
)
6705 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
6708 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
6710 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
6713 if (GetTypeId() == TYPEID_PLAYER
)
6714 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
6717 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
6719 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
6721 tAuraProcTriggerDamage
.push_back(aura
);
6723 tAuraProcTriggerDamage
.remove(aura
);
6726 uint32
Unit::GetCreatePowers( Powers power
) const
6728 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
6731 case POWER_MANA
: return GetCreateMana();
6732 case POWER_RAGE
: return 1000;
6733 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
6734 case POWER_ENERGY
: return 100;
6735 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
6741 void Unit::CleanupsBeforeDelete()
6743 if(m_uint32Values
) // only for fully created object
6745 m_Events
.KillAllEvents();
6748 getHostilRefManager().setOnlineOfflineState(false);
6754 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
6757 m_charmInfo
= new CharmInfo(charm
);
6761 CharmInfo::CharmInfo(Unit
* unit
)
6762 : m_unit(unit
), m_CommandState(COMMAND_STAY
), m_ReactSate(REACT_PASSIVE
), m_petnumber(0)
6764 for(int i
=0; i
<4; ++i
)
6766 m_charmspells
[i
].spellId
= 0;
6767 m_charmspells
[i
].active
= ACT_DISABLED
;
6771 void CharmInfo::InitPetActionBar()
6773 // the first 3 SpellOrActions are attack, follow and stay
6774 for(uint32 i
= 0; i
< 3; i
++)
6776 PetActionBar
[i
].Type
= ACT_COMMAND
;
6777 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
6779 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
6780 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
6782 for(uint32 i
=0; i
< 4; i
++)
6784 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
6785 PetActionBar
[i
+ 3].SpellOrAction
= 0;
6789 void CharmInfo::InitEmptyActionBar()
6791 for(uint32 x
= 1; x
< 10; ++x
)
6793 PetActionBar
[x
].Type
= ACT_CAST
;
6794 PetActionBar
[x
].SpellOrAction
= 0;
6796 PetActionBar
[0].Type
= ACT_COMMAND
;
6797 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
6800 void CharmInfo::InitPossessCreateSpells()
6802 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
6805 InitEmptyActionBar(); //charm action bar
6807 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6809 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
6810 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
6812 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
6816 void CharmInfo::InitCharmCreateSpells()
6818 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
6820 InitEmptyActionBar();
6826 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6828 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
6829 m_charmspells
[x
].spellId
= spellId
;
6834 if (IsPassiveSpell(spellId
))
6836 m_unit
->CastSpell(m_unit
, spellId
, true);
6837 m_charmspells
[x
].active
= ACT_PASSIVE
;
6841 ActiveStates newstate
;
6842 bool onlyselfcast
= true;
6843 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
6845 if(!spellInfo
) onlyselfcast
= false;
6846 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
6848 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
6849 onlyselfcast
= false;
6852 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
6853 newstate
= ACT_DISABLED
;
6855 newstate
= ACT_CAST
;
6857 AddSpellToAB(0, spellId
, newstate
);
6862 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
6864 for(uint8 i
= 0; i
< 10; i
++)
6866 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
6868 PetActionBar
[i
].SpellOrAction
= newid
;
6871 if(newstate
== ACT_DECIDE
)
6872 PetActionBar
[i
].Type
= ACT_DISABLED
;
6874 PetActionBar
[i
].Type
= newstate
;
6883 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
6885 if(IsPassiveSpell(spellid
))
6888 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6890 if(spellid
== m_charmspells
[x
].spellId
)
6892 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
6897 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
6899 m_petnumber
= petnumber
;
6901 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
6903 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
6906 bool Unit::isFrozen() const
6908 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
6909 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
6910 if( (*i
)->GetSpellProto()->School
== SPELL_SCHOOL_FROST
)