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 Unit::AuraTypeSet
GenerateAttakerProcAuraTypes()
60 static Unit::AuraTypeSet 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 Unit::AuraTypeSet
GenerateVictimProcAuraTypes()
70 static Unit::AuraTypeSet 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 Unit::AuraTypeSet attackerProcAuraTypes
= GenerateAttakerProcAuraTypes();
79 static Unit::AuraTypeSet victimProcAuraTypes
= GenerateVictimProcAuraTypes();
81 // auraTypes contains auras capable of proc'ing for attacker and victim
82 static Unit::AuraTypeSet
GenerateProcAuraTypes()
84 static Unit::AuraTypeSet auraTypes
= victimProcAuraTypes
;
85 auraTypes
.insert(attackerProcAuraTypes
.begin(),attackerProcAuraTypes
.end());
89 static Unit::AuraTypeSet 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)
406 RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH
);
407 RemoveSpellsCausingAura(SPELL_AURA_MOD_INVISIBILITY
);
409 // remove death simulation at damage
410 if(hasUnitState(UNIT_STAT_DIED
))
411 RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
413 //Script Event damage Deal
414 if( GetTypeId()== TYPEID_UNIT
&& ((Creature
*)this)->AI())
415 ((Creature
*)this)->AI()->DamageDeal(pVictim
, damage
);
416 //Script Event damage taken
417 if( pVictim
->GetTypeId()== TYPEID_UNIT
&& ((Creature
*)pVictim
)->AI() )
418 ((Creature
*)pVictim
)->AI()->DamageTaken(this, damage
);
422 // Rage from physical damage received .
423 if(cleanDamage
&& cleanDamage
->damage
&& damageSchool
==SPELL_SCHOOL_NORMAL
&& pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
424 ((Player
*)pVictim
)->RewardRage(cleanDamage
->damage
, 0, false);
429 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_FEAR
, damage
);
430 // root type spells do not dispell the root effect
431 if(!spellProto
|| spellProto
->Mechanic
!= MECHANIC_ROOT
)
432 pVictim
->RemoveSpellbyDamageTaken(SPELL_AURA_MOD_ROOT
, damage
);
434 if(pVictim
->GetTypeId() != TYPEID_PLAYER
)
436 //pVictim->SetInFront(this);
437 // no loot,xp,health if type 8 /critters/
438 if ( pVictim
->GetCreatureType() == CREATURE_TYPE_CRITTER
)
440 pVictim
->setDeathState(JUST_DIED
);
441 pVictim
->SetHealth(0);
442 pVictim
->CombatStop(true);
443 pVictim
->DeleteThreatList();
446 if(!pVictim
->isInCombat() && ((Creature
*)pVictim
)->AI())
447 ((Creature
*)pVictim
)->AI()->AttackStart(this);
450 DEBUG_LOG("DealDamageStart");
452 uint32 health
= pVictim
->GetHealth();
453 sLog
.outDetail("deal dmg:%d to health:%d ",damage
,health
);
455 // duel ends when player has 1 or less hp
456 bool duel_hasEnded
= false;
457 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)pVictim
)->duel
&& damage
>= (health
-1))
459 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
460 if(((Player
*)pVictim
)->duel
->opponent
==this || ((Player
*)pVictim
)->duel
->opponent
->GetGUID() == GetOwnerGUID())
463 duel_hasEnded
= true;
466 if(pVictim
!= this && damagetype
!= DOT
)
469 pVictim
->SetInCombat();
472 // Rage from Damage made (only from direct weapon damage)
473 if( cleanDamage
&& damagetype
==DIRECT_DAMAGE
&& this != pVictim
&& GetTypeId() == TYPEID_PLAYER
&& (getPowerType() == POWER_RAGE
))
475 uint32 weaponSpeedHitFactor
;
477 switch(cleanDamage
->attackType
)
481 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
482 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 7);
484 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
486 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
492 if(cleanDamage
->hitOutCome
== MELEE_HIT_CRIT
)
493 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 3.5f
);
495 weaponSpeedHitFactor
= uint32(GetAttackTime(cleanDamage
->attackType
)/1000.0f
* 1.75f
);
497 ((Player
*)this)->RewardRage(damage
, weaponSpeedHitFactor
, true);
506 if (health
<= damage
)
508 // battleground things
509 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (((Player
*)pVictim
)->InBattleGround()))
511 Player
*killed
= ((Player
*)pVictim
);
512 Player
*killer
= NULL
;
513 if(GetTypeId() == TYPEID_PLAYER
)
514 killer
= ((Player
*)this);
515 else if(GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
517 Unit
*owner
= GetOwner();
518 if(owner
->GetTypeId() == TYPEID_PLAYER
)
519 killer
= ((Player
*)owner
);
522 BattleGround
*bg
= sBattleGroundMgr
.GetBattleGround(killed
->GetBattleGroundId());
525 bg
->HandleKillPlayer(killed
, killer
); // drop flags and etc
527 bg
->UpdatePlayerScore(killed
, SCORE_DEATHS
, 1);
530 bg
->UpdatePlayerScore(killer
, SCORE_KILLS
, 1);
534 DEBUG_LOG("DealDamage: victim just died");
536 DEBUG_LOG("DealDamageAttackStop");
538 pVictim
->CombatStop(true);
540 DEBUG_LOG("SET JUST_DIED");
541 pVictim
->setDeathState(JUST_DIED
);
543 DEBUG_LOG("DealDamageHealth1");
544 pVictim
->SetHealth(0);
546 // Call KilledUnit for creatures
547 if (GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->AI())
548 ((Creature
*)this)->AI()->KilledUnit(pVictim
);
550 // 10% durability loss on death
551 // clean InHateListOf
552 if (pVictim
->GetTypeId() == TYPEID_PLAYER
)
554 if (GetTypeId() != TYPEID_PLAYER
&& durabilityLoss
)
556 DEBUG_LOG("We are dead, loosing 10 percents durability");
557 ((Player
*)pVictim
)->DurabilityLossAll(0.10);
558 // durability lost message
559 WorldPacket
data(SMSG_DURABILITY_DAMAGE_DEATH
, 0);
560 ((Player
*)pVictim
)->GetSession()->SendPacket(&data
);
562 pVictim
->getHostilRefManager().deleteReferences();
564 Pet
*pet
= pVictim
->GetPet();
565 if(pet
&& pVictim
->GetTypeId() != TYPEID_PLAYER
)
567 pet
->setDeathState(JUST_DIED
);
568 pet
->CombatStop(true);
570 pet
->addUnitState(UNIT_STAT_DIED
);
571 pet
->getHostilRefManager().deleteReferences();
574 else // creature died
576 DEBUG_LOG("DealDamageNotPlayer");
578 if(((Creature
*)pVictim
)->isPet())
579 pVictim
->getHostilRefManager().deleteReferences();
582 pVictim
->DeleteThreatList();
583 pVictim
->SetUInt32Value(UNIT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_LOOTABLE
);
585 // Call creature just died function
586 if (((Creature
*)pVictim
)->AI())
587 ((Creature
*)pVictim
)->AI()->JustDied(this);
590 //judge if GainXP, Pet kill like player kill,kill pet not like PvP
592 Player
*player
= NULL
;
594 if(GetTypeId() == TYPEID_PLAYER
)
596 player
= (Player
*)this;
597 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
602 if(player
->GetPetGUID() && (pet
= player
->GetPet()))
603 pet
->ClearInCombat();
605 if(player
->GetCharmGUID() && (pet
= player
->GetCharm()))
606 pet
->ClearInCombat();
608 // FIXME: or charmed (can be player). Maybe must be check before GetTypeId() == TYPEID_PLAYER
609 else if(GetCharmerOrOwnerGUID()) // Pet or timed creature, etc
612 Unit
* owner
= pet
->GetCharmerOrOwner();
614 if(owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
616 player
= (Player
*)owner
;
617 player
->ClearInCombat();
618 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
622 if(pet
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)pet
)->isPet())
624 uint32 petxp
= MaNGOS::XP::BaseGain(getLevel(), pVictim
->getLevel());
625 ((Pet
*)pet
)->GivePetXP(petxp
);
629 // self or owner of pet
634 // prepare data for near group iteration (PvP and !PvP cases
635 uint32 xp
= PvP
|| IsNoDamageXPArea(player
->GetAreaId()) ? 0 : MaNGOS::XP::Gain(player
, pVictim
);
636 bool honored_kill
= false;
638 Group
*pGroup
= player
->GetGroup();
641 uint32 count
= pGroup
->GetMemberCountForXPAtKill(pVictim
);
644 // skip in check PvP case (for speed, not used)
645 bool is_raid
= PvP
? false : MapManager::Instance().GetBaseMap(player
->GetMapId())->IsRaid() && pGroup
->isRaidGroup();
647 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
649 Player
*pGroupGuy
= pGroup
->GetMemberForXPAtKill(itr
->getSource(),pVictim
);
653 // honor can be in PvP and !PvP (racial leader) cases
654 if(pGroupGuy
->RewardHonor(pVictim
,count
) && player
==pGroupGuy
)
657 // xp and reputation only in !PvP case
660 // FIXME: xp/count for all in group at this moment, must be level dependent
661 float rate
= 1.0f
/count
;
663 // if with raid in raid dungeon then all receive full reputation at kill
664 pGroupGuy
->RewardReputation(pVictim
,is_raid
? 1.0f
: rate
);
666 uint32 itr_xp
= uint32(xp
*rate
);
668 pGroupGuy
->GiveXP(itr_xp
, pVictim
);
669 if(Pet
* pet
= player
->GetPet())
671 pet
->GivePetXP(itr_xp
/2);
674 // normal creature (not pet/etc) can be only in !PvP case
675 if(pVictim
->GetTypeId()==TYPEID_UNIT
)
676 pGroupGuy
->KilledMonster(pVictim
->GetEntry(), pVictim
->GetGUID());
683 // honor can be in PvP and !PvP (racial leader) cases
684 if(player
->RewardHonor(pVictim
,1))
687 // xp and reputation only in !PvP case
690 player
->RewardReputation(pVictim
,1);
691 player
->GiveXP(xp
, pVictim
);
692 if(Pet
* pet
= player
->GetPet())
697 // normal creature (not pet/etc) can be only in !PvP case
698 if(pVictim
->GetTypeId()==TYPEID_UNIT
)
699 player
->KilledMonster(pVictim
->GetEntry(),pVictim
->GetGUID());
703 if(xp
|| honored_kill
)
704 player
->ProcDamageAndSpell(pVictim
,PROC_FLAG_KILL_XP_GIVER
,PROC_FLAG_NONE
);
709 DEBUG_LOG("Monster kill Monster");
712 // last damage from duel opponent or opponent controlled creature?
715 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
716 Player
*he
= (Player
*)pVictim
;
720 CombatStop(); // for case killed by pet
721 if (IsNonMeleeSpellCasted(true))
722 InterruptNonMeleeSpells(true);
723 if(he
->duel
->opponent
!=this)
725 he
->duel
->opponent
->CombatStop();
726 if(he
->duel
->opponent
->IsNonMeleeSpellCasted(true))
727 he
->duel
->opponent
->InterruptNonMeleeSpells(true);
730 if(he
->IsNonMeleeSpellCasted(true))
731 he
->InterruptNonMeleeSpells(true);
736 else // if (health <= damage)
738 DEBUG_LOG("DealDamageAlive");
740 pVictim
->ModifyHealth(- (int32
)damage
);
742 // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
743 if(pVictim
->GetHealth()*5 < pVictim
->GetMaxHealth())
745 uint32 procVictim
= PROC_FLAG_NONE
;
747 // if just dropped below 20% (for CheatDeath)
748 if((pVictim
->GetHealth()+damage
)*5 > pVictim
->GetMaxHealth())
749 procVictim
= PROC_FLAG_LOW_HEALTH
;
751 ProcDamageAndSpell(pVictim
,PROC_FLAG_TARGET_LOW_HEALTH
,procVictim
);
754 if(damagetype
!= DOT
)
756 //start melee attacks only after melee hit
757 Attack(pVictim
,(damagetype
== DIRECT_DAMAGE
));
760 if(pVictim
->getTransForm() && pVictim
->hasUnitState(UNIT_STAT_CONFUSED
))
762 pVictim
->RemoveAurasDueToSpell(pVictim
->getTransForm());
763 pVictim
->setTransForm(0);
766 if (pVictim
->GetTypeId() != TYPEID_PLAYER
)
768 if(spellProto
&& IsDamageToThreatSpell(spellProto
))
770 pVictim
->AddThreat(this, damage
, damageSchool
, spellProto
);
772 else // victim is a player
774 // Rage from damage received
775 if(this != pVictim
&& pVictim
->GetTypeId() == TYPEID_PLAYER
&& pVictim
->getPowerType() == POWER_RAGE
)
777 uint32 rage_damage
= damage
+ (cleanDamage
? cleanDamage
->damage
: 0);
778 ((Player
*)pVictim
)->RewardRage(rage_damage
, 0, false);
781 // random durability for items (HIT)
782 if (urand(0,300) == 10)
784 DEBUG_LOG("HIT: We decrease durability with 5 percent");
785 ((Player
*)pVictim
)->DurabilityLossAll(0.05);
789 // TODO: Store auras by interrupt flag to speed this up.
790 AuraMap
& vAuras
= pVictim
->GetAuras();
791 for (AuraMap::iterator i
= vAuras
.begin(), next
; i
!= vAuras
.end(); i
= next
)
793 const SpellEntry
*se
= i
->second
->GetSpellProto();
795 if( se
->AuraInterruptFlags
& AURA_INTERRUPT_FLAG_DAMAGE
)
798 if (se
->procFlags
& (1<<3))
800 if (!roll_chance_i(se
->procChance
))
805 pVictim
->RemoveAurasDueToSpell(i
->second
->GetId());
806 // FIXME: this may cause the auras with proc chance to be rerolled several times
807 next
= vAuras
.begin();
812 if (damagetype
!= NODAMAGE
)
814 if(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
] && pVictim
->GetTypeId() == TYPEID_PLAYER
&& damage
)
816 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_CASTING
)
818 uint32 channelInterruptFlags
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->ChannelInterruptFlags
;
819 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
821 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
)));
822 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->DelayedChannel((int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
824 else if( (channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
826 sLog
.outDetail("Spell %u canceled at damage!",pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
);
827 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
830 else if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_DELAYED
)
831 // break channeled spell in delayed state on damage
833 sLog
.outDetail("Spell %u canceled at damage!",pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->Id
);
834 pVictim
->InterruptSpell(CURRENT_CHANNELED_SPELL
);
839 // last damage from duel opponent
842 assert(pVictim
->GetTypeId()==TYPEID_PLAYER
);
843 Player
*he
= (Player
*)pVictim
;
848 CombatStop(); // for case killed by pet
849 if(he
->duel
->opponent
!=this)
850 he
->duel
->opponent
->CombatStop();
853 he
->CastSpell(he
, 7267, true); // beg
858 DEBUG_LOG("DealDamageEnd");
861 void Unit::CastSpell(Unit
* Victim
, uint32 spellId
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
863 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
867 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
871 CastSpell(Victim
,spellInfo
,triggered
,castItem
,triggredByAura
, originalCaster
);
874 void Unit::CastSpell(Unit
* Victim
,SpellEntry
const *spellInfo
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
878 sLog
.outError("WORLD: unknown spell ");
883 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
885 Spell
*spell
= new Spell(this, spellInfo
, triggered
, triggredByAura
,originalCaster
);
887 SpellCastTargets targets
;
888 targets
.setUnitTarget( Victim
);
889 spell
->m_CastItem
= castItem
;
890 spell
->prepare(&targets
);
893 void Unit::CastCustomSpell(Unit
* Victim
,uint32 spellId
, int32
const* bp0
, int32
const* bp1
, int32
const* bp2
, bool triggered
, Item
*castItem
, Aura
* triggredByAura
, uint64 originalCaster
)
895 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
899 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
903 CastCustomSpell(Victim
,spellInfo
,bp0
,bp1
,bp2
,triggered
,castItem
,triggredByAura
, originalCaster
);
906 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
)
910 sLog
.outError("WORLD: unknown spell ");
915 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo
->Id
);
917 Spell
*spell
= new Spell(this, spellInfo
, triggered
, triggredByAura
,originalCaster
);
920 spell
->m_currentBasePoints
[0] = *bp0
;
923 spell
->m_currentBasePoints
[1] = *bp1
;
926 spell
->m_currentBasePoints
[2] = *bp2
;
928 SpellCastTargets targets
;
929 targets
.setUnitTarget( Victim
);
930 spell
->m_CastItem
= castItem
;
931 spell
->prepare(&targets
);
934 void Unit::DealDamageBySchool(Unit
*pVictim
, SpellEntry
const *spellInfo
, uint32
*damage
, CleanDamage
*cleanDamage
, bool *crit
, bool isTriggeredSpell
)
937 // TODO this in only generic way, check for exceptions
938 DEBUG_LOG("DealDamageBySchool (BEFORE) SCHOOL %u >> DMG:%u", spellInfo
->School
, *damage
);
941 switch (spellInfo
->School
)
943 // Physical damage school
944 case SPELL_SCHOOL_NORMAL
:
946 // Calculate physical outcome
947 MeleeHitOutcome outcome
;
948 outcome
= RollPhysicalOutcomeAgainst(pVictim
, BASE_ATTACK
, spellInfo
);
950 //Used to store the Hit Outcome
951 cleanDamage
->hitOutCome
= outcome
;
953 // Return miss first (sends miss message)
954 if(outcome
== MELEE_HIT_MISS
)
956 SendAttackStateUpdate(HITINFO_MISS
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
959 if(GetTypeId()== TYPEID_PLAYER
)
960 ((Player
*)this)->UpdateWeaponSkill(BASE_ATTACK
);
962 CastMeleeProcDamageAndSpell(pVictim
,0,BASE_ATTACK
,MELEE_HIT_MISS
,spellInfo
,isTriggeredSpell
);
966 // Hitinfo, Victimstate
967 uint32 hitInfo
, victimState
;
968 hitInfo
= HITINFO_NORMALSWING
;
970 //Calculate armor mitigation
971 uint32 damageAfterArmor
;
972 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
973 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
974 *damage
= damageAfterArmor
;
982 // Resilience - reduce crit damage by 2x%
983 uint32 resilienceReduction
= uint32(pVictim
->m_modResilience
* 2/100 * (*damage
));
984 cleanDamage
->damage
+= resilienceReduction
;
985 *damage
-= resilienceReduction
;
987 hitInfo
|= HITINFO_CRITICALHIT
;
990 case MELEE_HIT_PARRY
:
992 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
994 victimState
= VICTIMSTATE_PARRY
;
996 // Counter-attack ( explained in Unit::DoAttackDamage() )
999 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1000 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1002 // Reduce attack time
1003 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1005 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
) * 0.20;
1006 float percent60
= 3 * percent20
;
1007 if(offtime
> percent20
&& offtime
<= percent60
)
1009 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(percent20
));
1011 else if(offtime
> percent60
)
1013 offtime
-= 2 * percent20
;
1014 pVictim
->setAttackTimer(OFF_ATTACK
, uint32(offtime
));
1019 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
) * 0.20;
1020 float percent60
= 3 * percent20
;
1021 if(basetime
> percent20
&& basetime
<= percent60
)
1023 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(percent20
));
1025 else if(basetime
> percent60
)
1027 basetime
-= 2 * percent20
;
1028 pVictim
->setAttackTimer(BASE_ATTACK
, uint32(basetime
));
1033 // Update victim defense ?
1034 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1035 ((Player
*)pVictim
)->UpdateDefense();
1038 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1039 pVictim
->ModifyAuraState(AURA_STATE_PARRY
, true);
1042 case MELEE_HIT_DODGE
:
1044 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1045 ((Player
*)pVictim
)->UpdateDefense();
1047 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1049 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1050 victimState
= VICTIMSTATE_DODGE
;
1053 case MELEE_HIT_BLOCK
:
1055 uint32 blocked_amount
;
1056 blocked_amount
= uint32(pVictim
->GetShieldBlockValue());
1057 if (blocked_amount
>= *damage
)
1059 hitInfo
|= HITINFO_SWINGNOHITSOUND
;
1060 victimState
= VICTIMSTATE_BLOCKS
;
1061 cleanDamage
->damage
+= *damage
; // To Help Calculate Rage
1066 // To Help Calculate Rage
1067 cleanDamage
->damage
+= blocked_amount
;
1068 *damage
= *damage
- blocked_amount
;
1073 case MELEE_HIT_MISS
:
1074 case MELEE_HIT_GLANCING
:
1075 case MELEE_HIT_CRUSHING
:
1076 case MELEE_HIT_NORMAL
:
1080 // Update attack state
1081 SendAttackStateUpdate(victimState
? hitInfo
|victimState
: hitInfo
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
1083 // do all damage=0 cases here
1085 CastMeleeProcDamageAndSpell(pVictim
,0,BASE_ATTACK
,outcome
,spellInfo
,isTriggeredSpell
);
1090 case SPELL_SCHOOL_HOLY
:
1091 case SPELL_SCHOOL_FIRE
:
1092 case SPELL_SCHOOL_NATURE
:
1093 case SPELL_SCHOOL_FROST
:
1094 case SPELL_SCHOOL_SHADOW
:
1095 case SPELL_SCHOOL_ARCANE
:
1097 //Spell miss (sends resist message)
1098 if(SpellMissChanceCalc(pVictim
) > urand(0,10000))
1100 cleanDamage
->damage
= 0;
1102 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, spellInfo
,isTriggeredSpell
);
1103 SendAttackStateUpdate(HITINFO_RESIST
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
), 0, 0,0,1,0);
1107 // Calculate damage bonus
1108 *damage
= SpellDamageBonus(pVictim
, spellInfo
, *damage
, SPELL_DIRECT_DAMAGE
);
1110 // Calculate critical bonus
1111 *crit
= SpellCriticalBonus(spellInfo
, (int32
*)damage
, pVictim
);
1112 cleanDamage
->hitOutCome
= MELEE_HIT_CRIT
;
1114 // spell proc all magic damage==0 case in this function
1118 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1119 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1121 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, 0, spellInfo
, isTriggeredSpell
);
1127 // TODO this in only generic way, check for exceptions
1128 DEBUG_LOG("DealDamageBySchool (AFTER) SCHOOL %u >> DMG:%u", spellInfo
->School
, *damage
);
1131 void Unit::SpellNonMeleeDamageLog(Unit
*pVictim
, uint32 spellID
, uint32 damage
, bool isTriggeredSpell
, bool useSpellDamage
)
1133 if(!this || !pVictim
)
1135 if(!this->isAlive() || !pVictim
->isAlive())
1138 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellID
);
1142 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1146 DealDamageBySchool(pVictim
, spellInfo
, &damage
, &cleanDamage
, &crit
, isTriggeredSpell
);
1148 // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealDamageBySchool)
1151 // Calculate absorb & resists
1155 CalcAbsorbResist(pVictim
,SpellSchools(spellInfo
->School
), damage
, &absorb
, &resist
);
1157 // Only send absorbed message if we actually absorbed some damage
1160 // Handle absorb &Â resists
1161 if(damage
<= absorb
+ resist
&& absorb
)
1163 SendAttackStateUpdate(HITINFO_ABSORB
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
),damage
, absorb
,resist
,1,0);
1166 else if(damage
<= resist
) // If we didn't fully absorb check if we fully resisted
1168 ProcDamageAndSpell(pVictim
, PROC_FLAG_TARGET_RESISTS
, PROC_FLAG_RESIST_SPELL
, 0, spellInfo
,isTriggeredSpell
);
1169 SendAttackStateUpdate(HITINFO_RESIST
|HITINFO_SWINGNOHITSOUND
, pVictim
, 1, SpellSchools(spellInfo
->School
), damage
, absorb
,resist
,1,0);
1175 sLog
.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u",
1176 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, spellID
, absorb
,resist
);
1177 SendSpellNonMeleeDamageLog(pVictim
, spellID
, damage
, SpellSchools(spellInfo
->School
), absorb
, resist
, false, 0, crit
);
1180 DealDamage(pVictim
, (damage
-absorb
-resist
), &cleanDamage
, SPELL_DIRECT_DAMAGE
, SpellSchools(spellInfo
->School
), spellInfo
, 0, true);
1183 uint32 procAttacker
= PROC_FLAG_HIT_SPELL
;
1184 uint32 procVictim
= (PROC_FLAG_STRUCK_SPELL
|PROC_FLAG_TAKE_DAMAGE
);
1188 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
1189 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
1192 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, (damage
-absorb
-resist
), spellInfo
, isTriggeredSpell
);
1196 // all spell proc for 0 normal and magic damage called in DealDamageBySchool
1199 if(cleanDamage
.damage
)
1200 // Rage from damage received.
1201 if(pVictim
->GetTypeId() == TYPEID_PLAYER
&& (pVictim
->getPowerType() == POWER_RAGE
))
1202 ((Player
*)pVictim
)->RewardRage(cleanDamage
.damage
, 0, false);
1206 void Unit::PeriodicAuraLog(Unit
*pVictim
, SpellEntry
const *spellProto
, Modifier
*mod
, uint8 effect_idx
)
1208 uint32 procFlag
= 0;
1209 if(!this || !pVictim
|| !isAlive() || !pVictim
->isAlive())
1215 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1216 uint32 pdamage
= mod
->m_amount
;
1218 if(mod
->m_auraname
!= SPELL_AURA_PERIODIC_HEAL
&& mod
->m_auraname
!= SPELL_AURA_OBS_MOD_HEALTH
)
1220 //Calculate armor mitigation if it is a physical spell
1221 if (spellProto
->School
== SPELL_SCHOOL_NORMAL
)
1223 uint32 pdamageReductedArmor
= CalcArmorReducedDamage(pVictim
, pdamage
);
1224 cleanDamage
.damage
+= pdamage
- pdamageReductedArmor
;
1225 pdamage
= pdamageReductedArmor
;
1228 CalcAbsorbResist(pVictim
, SpellSchools(spellProto
->School
), pdamage
, &absorb
, &resist
);
1231 sLog
.outDetail("PeriodicAuraLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
1232 GetGUIDLow(), GetTypeId(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), pdamage
, spellProto
->Id
,absorb
);
1234 switch(mod
->m_auraname
)
1236 case SPELL_AURA_PERIODIC_DAMAGE
:
1237 case SPELL_AURA_PERIODIC_DAMAGE_PERCENT
:
1239 pdamage
= SpellDamageBonus(pVictim
,spellProto
,pdamage
,DOT
);
1241 if(mod
->m_auraname
== SPELL_AURA_PERIODIC_DAMAGE_PERCENT
)
1242 pdamage
= GetHealth()*(100+mod
->m_amount
)/100;
1244 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1245 data
.append(pVictim
->GetPackGUID());
1246 data
.append(GetPackGUID());
1247 data
<< uint32(spellProto
->Id
);
1249 data
<< uint32(mod
->m_auraname
);
1250 data
<< (uint32
)pdamage
;
1251 data
<< (uint32
)spellProto
->School
;
1252 data
<< (uint32
)absorb
;
1253 data
<< (uint32
)resist
;
1254 SendMessageToSet(&data
,true);
1256 DealDamage(pVictim
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), &cleanDamage
, DOT
, SpellSchools(spellProto
->School
), spellProto
, procFlag
, true);
1257 ProcDamageAndSpell(pVictim
, PROC_FLAG_HIT_SPELL
, PROC_FLAG_TAKE_DAMAGE
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), spellProto
);
1260 case SPELL_AURA_PERIODIC_HEAL
:
1261 case SPELL_AURA_OBS_MOD_HEALTH
:
1263 pdamage
= SpellHealingBonus(spellProto
, pdamage
, DOT
, pVictim
);
1265 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1266 data
.append(pVictim
->GetPackGUID());
1267 data
.append(GetPackGUID());
1268 data
<< uint32(spellProto
->Id
);
1270 data
<< uint32(mod
->m_auraname
);
1271 data
<< (uint32
)pdamage
;
1272 SendMessageToSet(&data
,true);
1274 int32 gain
= pVictim
->ModifyHealth(pdamage
);
1275 pVictim
->getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1277 // heal for caster damage
1278 if(pVictim
!=this && spellProto
->SpellVisual
==163)
1280 uint32 dmg
= spellProto
->manaPerSecond
;
1281 if(GetHealth() <= dmg
&& GetTypeId()==TYPEID_PLAYER
)
1283 RemoveAurasDueToSpell(spellProto
->Id
);
1285 // finish current generic/channeling spells, don't affect autorepeat
1286 if(m_currentSpells
[CURRENT_GENERIC_SPELL
])
1288 m_currentSpells
[CURRENT_GENERIC_SPELL
]->finish();
1290 if(m_currentSpells
[CURRENT_CHANNELED_SPELL
])
1292 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SendChannelUpdate(0);
1293 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->finish();
1298 SendSpellNonMeleeDamageLog(this, spellProto
->Id
, gain
, SpellSchools(spellProto
->School
), 0, 0, false, 0, false);
1299 DealDamage(this, gain
, &cleanDamage
, NODAMAGE
, SpellSchools(spellProto
->School
), spellProto
, PROC_FLAG_HEAL
, true);
1303 if(mod
->m_auraname
== SPELL_AURA_PERIODIC_HEAL
&& pVictim
!= this)
1304 ProcDamageAndSpell(pVictim
, PROC_FLAG_HEAL
, PROC_FLAG_HEALED
, pdamage
, spellProto
);
1307 case SPELL_AURA_PERIODIC_LEECH
:
1309 float multiplier
= spellProto
->EffectMultipleValue
[effect_idx
] > 0 ? spellProto
->EffectMultipleValue
[effect_idx
] : 1;
1310 uint32 pdamage
= mod
->m_amount
;
1312 pdamage
= SpellDamageBonus(pVictim
,spellProto
,pdamage
,DOT
);
1314 if(pVictim
->GetHealth() < pdamage
)
1315 pdamage
= uint32(pVictim
->GetHealth());
1317 SendSpellNonMeleeDamageLog(pVictim
, spellProto
->Id
, pdamage
, SpellSchools(spellProto
->School
), absorb
, resist
, false, 0);
1318 DealDamage(pVictim
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), &cleanDamage
, DOT
, SpellSchools(spellProto
->School
), spellProto
, procFlag
, false);
1319 ProcDamageAndSpell(pVictim
, PROC_FLAG_HIT_SPELL
, PROC_FLAG_TAKE_DAMAGE
, (pdamage
<= absorb
+resist
) ? 0 : (pdamage
-absorb
-resist
), spellProto
);
1320 if (!pVictim
->isAlive() && IsNonMeleeSpellCasted(false))
1322 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
1324 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->Id
== spellProto
->Id
)
1325 m_currentSpells
[i
]->cancel();
1329 int32 gain
= ModifyHealth(int32(pdamage
* multiplier
));
1330 getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1332 if(GetTypeId() == TYPEID_PLAYER
)
1333 SendHealSpellOnPlayer(this, spellProto
->Id
, uint32(pdamage
* multiplier
));
1336 case SPELL_AURA_PERIODIC_MANA_LEECH
:
1338 if(mod
->m_miscvalue
< 0 || mod
->m_miscvalue
> 4)
1341 Powers power
= Powers(mod
->m_miscvalue
);
1343 int32 drain_amount
= pVictim
->GetPower(power
) > pdamage
? pdamage
: pVictim
->GetPower(power
);
1345 pVictim
->ModifyPower(power
, -drain_amount
);
1347 float gain_multiplier
= GetMaxPower(power
) > 0 ? spellProto
->EffectMultipleValue
[effect_idx
] : 0;
1349 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1350 data
.append(pVictim
->GetPackGUID());
1351 data
.append(GetPackGUID());
1352 data
<< uint32(spellProto
->Id
);
1354 data
<< uint32(mod
->m_auraname
);
1355 data
<< (uint32
)power
; // power type
1356 data
<< (uint32
)drain_amount
;
1357 data
<< (float)gain_multiplier
;
1358 SendMessageToSet(&data
,true);
1360 int32 gain_amount
= int32(drain_amount
*gain_multiplier
);
1364 int32 gain
= ModifyPower(power
,gain_amount
);
1365 pVictim
->AddThreat(this, float(gain
) * 0.5f
, SpellSchools(spellProto
->School
), spellProto
);
1369 case SPELL_AURA_PERIODIC_ENERGIZE
:
1371 if(mod
->m_miscvalue
< 0 || mod
->m_miscvalue
> 4)
1374 Powers power
= Powers(mod
->m_miscvalue
);
1376 if(pVictim
->GetMaxPower(power
) == 0)
1379 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1380 data
.append(pVictim
->GetPackGUID());
1381 data
.append(GetPackGUID());
1382 data
<< uint32(spellProto
->Id
);
1384 data
<< uint32(mod
->m_auraname
);
1385 data
<< (uint32
)power
; // power type
1386 data
<< (uint32
)mod
->m_amount
;
1387 SendMessageToSet(&data
,true);
1389 int32 gain
= pVictim
->ModifyPower(power
,mod
->m_amount
);
1390 pVictim
->getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1393 case SPELL_AURA_OBS_MOD_MANA
:
1395 if(GetMaxPower(POWER_MANA
) == 0)
1398 WorldPacket
data(SMSG_PERIODICAURALOG
, (21+16));// we guess size
1399 data
.append(pVictim
->GetPackGUID());
1400 data
.append(GetPackGUID());
1401 data
<< uint32(spellProto
->Id
);
1403 data
<< uint32(mod
->m_auraname
);
1404 data
<< (uint32
)mod
->m_amount
;
1405 data
<< (uint32
)0; // ?
1406 SendMessageToSet(&data
,true);
1408 int32 gain
= ModifyPower(POWER_MANA
, mod
->m_amount
);
1409 getHostilRefManager().threatAssist(this, float(gain
) * 0.5f
, spellProto
);
1415 void Unit::HandleEmoteCommand(uint32 anim_id
)
1417 WorldPacket
data( SMSG_EMOTE
, 12 );
1418 data
<< anim_id
<< GetGUID();
1419 WPAssert(data
.size() == 12);
1421 SendMessageToSet(&data
, true);
1424 uint32
Unit::CalcArmorReducedDamage(Unit
* pVictim
, const uint32 damage
)
1426 uint32 newdamage
= 0;
1427 float armor
= pVictim
->GetArmor();
1429 float tmpvalue
= 0.0;
1430 if(getLevel() <= 59) //Level 1-59
1431 tmpvalue
= armor
/ (armor
+ 400.0 + 85.0 * getLevel());
1432 else if(getLevel() < 70) //Level 60-69
1433 tmpvalue
= armor
/ (armor
- 22167.5 + 467.5 * getLevel());
1435 tmpvalue
= armor
/ (armor
+ 10557.5);
1441 newdamage
= uint32(damage
- (damage
* tmpvalue
));
1443 return (newdamage
> 1) ? newdamage
: 1;
1446 void Unit::CalcAbsorbResist(Unit
*pVictim
,SpellSchools school
, const uint32 damage
, uint32
*absorb
, uint32
*resist
)
1448 if(!pVictim
|| !pVictim
->isAlive() || !damage
)
1451 // Magic damage, check for resists
1452 if (school
!= SPELL_SCHOOL_NORMAL
)
1454 int32 tmpvalue2
= pVictim
->GetResistance(school
);
1455 AuraList
const& mModTargetRes
= GetAurasByType(SPELL_AURA_MOD_TARGET_RESISTANCE
);
1456 for(AuraList::const_iterator i
= mModTargetRes
.begin(); i
!= mModTargetRes
.end(); ++i
)
1457 if ((*i
)->GetModifier()->m_miscvalue
& int32(1 << school
))
1458 tmpvalue2
+= (*i
)->GetModifier()->m_amount
;
1459 if (tmpvalue2
< 0) tmpvalue2
= 0;
1460 *resist
+= uint32(damage
*tmpvalue2
*0.0025*pVictim
->getLevel()/getLevel());
1461 if(*resist
> damage
)
1467 int32 RemainingDamage
= damage
- *resist
;
1468 int32 currentAbsorb
, manaReduction
, maxAbsorb
;
1469 float manaMultiplier
;
1471 if (school
== SPELL_SCHOOL_NORMAL
)
1473 AuraList
const& vManaShield
= pVictim
->GetAurasByType(SPELL_AURA_MANA_SHIELD
);
1474 for(AuraList::const_iterator i
= vManaShield
.begin(), next
; i
!= vManaShield
.end() && RemainingDamage
>= 0; i
= next
)
1477 if (RemainingDamage
- (*i
)->m_absorbDmg
>= 0)
1478 currentAbsorb
= (*i
)->m_absorbDmg
;
1480 currentAbsorb
= RemainingDamage
;
1482 manaMultiplier
= (*i
)->GetSpellProto()->EffectMultipleValue
[(*i
)->GetEffIndex()];
1483 maxAbsorb
= int32(pVictim
->GetPower(POWER_MANA
) / manaMultiplier
);
1484 if (currentAbsorb
> maxAbsorb
)
1485 currentAbsorb
= maxAbsorb
;
1487 (*i
)->m_absorbDmg
-= currentAbsorb
;
1488 if((*i
)->m_absorbDmg
<= 0)
1490 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1491 next
= vManaShield
.begin();
1494 manaReduction
= int32(currentAbsorb
* manaMultiplier
);
1495 pVictim
->ApplyPowerMod(POWER_MANA
, manaReduction
, false);
1497 RemainingDamage
-= currentAbsorb
;
1501 AuraList
const& vSchoolAbsorb
= pVictim
->GetAurasByType(SPELL_AURA_SCHOOL_ABSORB
);
1502 for(AuraList::const_iterator i
= vSchoolAbsorb
.begin(), next
; i
!= vSchoolAbsorb
.end() && RemainingDamage
>= 0; i
= next
)
1505 if ((*i
)->GetModifier()->m_miscvalue
& int32(1<<school
))
1507 if (RemainingDamage
- (*i
)->m_absorbDmg
>= 0)
1509 currentAbsorb
= (*i
)->m_absorbDmg
;
1510 pVictim
->RemoveAurasDueToSpell((*i
)->GetId());
1511 next
= vSchoolAbsorb
.begin();
1515 currentAbsorb
= RemainingDamage
;
1516 (*i
)->m_absorbDmg
-= RemainingDamage
;
1519 RemainingDamage
-= currentAbsorb
;
1523 *absorb
= damage
- RemainingDamage
- *resist
;
1526 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
)
1528 pVictim
->ModifyAuraState(AURA_STATE_PARRY
, false);
1529 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, false);
1530 ModifyAuraState(AURA_STATE_CRIT
, false);
1532 MeleeHitOutcome outcome
;
1534 // If is casted Melee spell, calculate like physical
1536 outcome
= RollMeleeOutcomeAgainst (pVictim
, attType
);
1538 outcome
= RollPhysicalOutcomeAgainst (pVictim
, attType
, spellCasted
);
1540 if (outcome
== MELEE_HIT_MISS
)
1542 *hitInfo
|= HITINFO_MISS
;
1544 cleanDamage
->damage
= 0;
1545 if(GetTypeId()== TYPEID_PLAYER
)
1546 ((Player
*)this)->UpdateWeaponSkill(attType
);
1550 /// If this is a creature and it attacks from behind it has a probability to daze it's victim
1551 if( (outcome
==MELEE_HIT_CRIT
|| outcome
==MELEE_HIT_CRUSHING
|| outcome
==MELEE_HIT_NORMAL
|| outcome
==MELEE_HIT_GLANCING
) &&
1552 GetTypeId() != TYPEID_PLAYER
&& !((Creature
*)this)->GetCharmerOrOwnerGUID() && !pVictim
->HasInArc(M_PI
, this) )
1554 // -probability is between 0% and 40%
1556 float Probability
= 20;
1558 //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1559 if( pVictim
->getLevel() < 30 )
1560 Probability
= 0.65f
*pVictim
->getLevel()+0.5;
1562 uint32 VictimDefense
=pVictim
->GetDefenseSkillValue();
1563 uint32 AttackerMeleeSkill
=GetUnitMeleeSkill();
1565 Probability
*= AttackerMeleeSkill
/(float)VictimDefense
;
1567 if(Probability
> 40)
1570 if(roll_chance_f(Probability
))
1571 CastSpell(pVictim
, 1604, true);
1574 *damage
+= CalculateDamage (attType
);
1576 //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL
1577 if (damageType
== SPELL_SCHOOL_NORMAL
)
1579 uint32 damageAfterArmor
= CalcArmorReducedDamage(pVictim
, *damage
);
1580 cleanDamage
->damage
+= *damage
- damageAfterArmor
;
1581 *damage
= damageAfterArmor
;
1583 // Instant Attacks (Spellmods)
1584 // TODO: AP bonus related to mainhand weapon
1586 if(GetTypeId()== TYPEID_PLAYER
)
1587 ((Player
*)this)->ApplySpellMod(spellCasted
->Id
, SPELLMOD_DAMAGE
, *damage
);
1589 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1590 ((Player
*)this)->UpdateCombatSkills(pVictim
, attType
, outcome
, false);
1592 if(GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetTypeId() == TYPEID_PLAYER
)
1593 ((Player
*)pVictim
)->UpdateCombatSkills(this, attType
, outcome
, true);
1597 case MELEE_HIT_CRIT
:
1600 *hitInfo
= HITINFO_CRITICALHIT
| HITINFO_NORMALSWING2
| 0x8;
1604 crit_bonus
= *damage
;
1606 // Apply crit_damage bonus for melee spells
1607 if (GetTypeId() == TYPEID_PLAYER
&& spellCasted
)
1609 ((Player
*)this)->ApplySpellMod(spellCasted
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
1612 *damage
+= crit_bonus
;
1614 // Resilience - reduce crit damage by 2x%
1615 uint32 resilienceReduction
;
1616 resilienceReduction
= uint32(pVictim
->m_modResilience
* 2/100 * (*damage
));
1617 *damage
-= resilienceReduction
;
1618 cleanDamage
->damage
+= resilienceReduction
;
1620 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& pVictim
->GetCreatureType() != CREATURE_TYPE_CRITTER
)
1621 ((Player
*)this)->UpdateWeaponSkill(attType
);
1623 ModifyAuraState(AURA_STATE_CRIT
, true);
1625 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL
);
1628 case MELEE_HIT_PARRY
:
1629 if(attType
== RANGED_ATTACK
) //range attack - no parry
1632 cleanDamage
->damage
+= *damage
;
1634 *victimState
= VICTIMSTATE_PARRY
;
1636 // instant (maybe with small delay) counter attack
1638 float offtime
= float(pVictim
->getAttackTimer(OFF_ATTACK
));
1639 float basetime
= float(pVictim
->getAttackTimer(BASE_ATTACK
));
1641 // after parry nearest next attack time will reduced at %40 from full attack time.
1642 // The delay cannot be reduced to less than 20% of your weapon’s base swing delay.
1643 if (pVictim
->haveOffhandWeapon() && offtime
< basetime
)
1645 float percent20
= pVictim
->GetAttackTime(OFF_ATTACK
)*0.20;
1646 float percent60
= 3*percent20
;
1647 // set to 20% if in range 20%...20+40% of full time
1648 if(offtime
> percent20
&& offtime
<= percent60
)
1650 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(percent20
));
1652 // decrease at %40 from full time
1653 else if(offtime
> percent60
)
1655 offtime
-= 2*percent20
;
1656 pVictim
->setAttackTimer(OFF_ATTACK
,uint32(offtime
));
1662 float percent20
= pVictim
->GetAttackTime(BASE_ATTACK
)*0.20;
1663 float percent60
= 3*percent20
;
1664 // set to 20% if in range 20%...20+40% of full time
1665 if(basetime
> percent20
&& basetime
<= percent60
)
1667 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(percent20
));
1669 // decrease at %40 from full time
1670 else if(basetime
> percent60
)
1672 basetime
-= 2*percent20
;
1673 pVictim
->setAttackTimer(BASE_ATTACK
,uint32(basetime
));
1679 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1680 ((Player
*)pVictim
)->UpdateDefense();
1682 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1683 pVictim
->ModifyAuraState(AURA_STATE_PARRY
,true);
1684 if (pVictim
->getClass() != CLASS_HUNTER
) // Mongoose Bite
1685 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1687 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1690 case MELEE_HIT_DODGE
:
1691 if(attType
== RANGED_ATTACK
) //range attack - no dodge
1693 cleanDamage
->damage
+= *damage
;
1695 *victimState
= VICTIMSTATE_DODGE
;
1697 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1698 ((Player
*)pVictim
)->UpdateDefense();
1700 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1702 if (pVictim
->getClass() != CLASS_ROGUE
) // Riposte
1703 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
, true);
1705 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1708 case MELEE_HIT_BLOCK
:
1709 *blocked_amount
= uint32(pVictim
->GetShieldBlockValue() + (pVictim
->GetStat(STAT_STRENGTH
) / 20.0f
) -1);
1711 if (pVictim
->GetUnitBlockChance())
1712 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD
);
1714 pVictim
->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED
);
1716 //Only set VICTIMSTATE_BLOCK on a full block
1717 if (*blocked_amount
>= *damage
)
1719 *victimState
= VICTIMSTATE_BLOCKS
;
1720 *blocked_amount
= *damage
;
1723 if(pVictim
->GetTypeId() == TYPEID_PLAYER
)
1724 ((Player
*)pVictim
)->UpdateDefense();
1725 pVictim
->ModifyAuraState(AURA_STATE_DEFENSE
,true);
1728 case MELEE_HIT_GLANCING
:
1730 float reducePercent
= 1.0f
; //damage factor
1732 // calculate base values and mods
1733 float baseLowEnd
= 1.3;
1734 float baseHighEnd
= 1.2;
1735 switch(getClass()) // lowering base values for casters
1747 float maxLowEnd
= 0.6;
1748 switch(getClass()) // upper for melee classes
1752 maxLowEnd
= 0.91; //If the attacker is a melee class then instead the lower value of 0.91
1756 int32 diff
= pVictim
->GetDefenseSkillValue() - GetWeaponSkillValue(attType
);
1757 float lowEnd
= baseLowEnd
- ( 0.05f
* diff
);
1758 float highEnd
= baseHighEnd
- ( 0.03f
* diff
);
1760 // apply max/min bounds
1761 if ( lowEnd
< 0.01f
) //the low end must not go bellow 0.01f
1763 else if ( lowEnd
> maxLowEnd
) //the smaller value of this and 0.6 is kept as the low end
1766 if ( highEnd
< 0.2f
) //high end limits
1768 if ( highEnd
> 0.99f
)
1771 if(lowEnd
> highEnd
) // prevent negative range size
1774 reducePercent
= lowEnd
+ rand_norm() * ( highEnd
- lowEnd
);
1776 *damage
= uint32(reducePercent
* *damage
);
1777 cleanDamage
->damage
+= *damage
;
1778 *hitInfo
|= HITINFO_GLANCING
;
1781 case MELEE_HIT_CRUSHING
:
1783 // 150% normal damage
1784 *damage
+= (*damage
/ 2);
1785 cleanDamage
->damage
= *damage
;
1786 *hitInfo
|= HITINFO_CRUSHING
;
1787 // TODO: victimState, victim animation?
1794 // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block
1795 if(*victimState
!= VICTIMSTATE_BLOCKS
)
1797 MeleeDamageBonus(pVictim
, damage
,attType
);
1798 CalcAbsorbResist(pVictim
, damageType
, *damage
-*blocked_amount
, absorbDamage
, resistDamage
);
1801 if (*absorbDamage
) *hitInfo
|= HITINFO_ABSORB
;
1802 if (*resistDamage
) *hitInfo
|= HITINFO_RESIST
;
1803 cleanDamage
+= *blocked_amount
;
1805 if (*damage
<= *absorbDamage
+ *resistDamage
+ *blocked_amount
)
1807 //*hitInfo = 0x00010020;
1808 //*hitInfo |= HITINFO_SWINGNOHITSOUND;
1810 CastMeleeProcDamageAndSpell(pVictim
, 0, attType
, outcome
, spellCasted
, isTriggeredSpell
);
1814 CastMeleeProcDamageAndSpell(pVictim
, (*damage
- *absorbDamage
- *resistDamage
- *blocked_amount
), attType
, outcome
, spellCasted
, isTriggeredSpell
);
1816 // victim's damage shield
1817 // yet another hack to fix crashes related to the aura getting removed during iteration
1818 std::set
<Aura
*> alreadyDone
;
1819 uint32 removedAuras
= pVictim
->m_removedAuras
;
1820 AuraList
const& vDamageShields
= pVictim
->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD
);
1821 for(AuraList::const_iterator i
= vDamageShields
.begin(), next
= vDamageShields
.begin(); i
!= vDamageShields
.end(); i
= next
)
1824 if (alreadyDone
.find(*i
) == alreadyDone
.end())
1826 alreadyDone
.insert(*i
);
1827 pVictim
->SpellNonMeleeDamageLog(this, (*i
)->GetId(), (*i
)->GetModifier()->m_amount
, false, false);
1828 if (pVictim
->m_removedAuras
> removedAuras
)
1830 removedAuras
= pVictim
->m_removedAuras
;
1831 next
= vDamageShields
.begin();
1836 if (pVictim
->GetTypeId() == TYPEID_PLAYER
&& *damage
)
1838 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
1840 // skip channeled spell (processed differently below)
1841 if (i
== CURRENT_CHANNELED_SPELL
)
1844 if(pVictim
->m_currentSpells
[i
])
1846 sLog
.outDetail("Spell Delayed!%d",(int32
)(0.25f
* pVictim
->m_currentSpells
[i
]->casttime
));
1847 pVictim
->m_currentSpells
[i
]->Delayed((int32
)(0.25f
* pVictim
->m_currentSpells
[i
]->casttime
));
1851 // process channeled spell separately
1852 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
])
1854 if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_CASTING
)
1856 uint32 channelInterruptFlags
= pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
->ChannelInterruptFlags
;
1857 if( channelInterruptFlags
& CHANNEL_FLAG_DELAY
)
1859 sLog
.outDetail("Spell Delayed!%d",(int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
1860 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->DelayedChannel((int32
)(0.25f
* GetDuration(pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->m_spellInfo
)));
1863 else if( !(channelInterruptFlags
& (CHANNEL_FLAG_DAMAGE
| CHANNEL_FLAG_DAMAGE2
)) )
1866 sLog
.outDetail("Spell Canceled!");
1867 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
1869 else if (pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() == SPELL_STATE_DELAYED
)
1871 // break channeled spell in delayed state on damage
1872 sLog
.outDetail("Spell Canceled!");
1873 pVictim
->m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
1879 void Unit::AttackerStateUpdate (Unit
*pVictim
, WeaponAttackType attType
, bool isTriggered
)
1881 if(hasUnitState(UNIT_STAT_CONFUSED
| UNIT_STAT_STUNDED
| UNIT_STAT_FLEEING
) || HasFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PACIFIED
) )
1884 if (!pVictim
->isAlive())
1889 if(IsNonMeleeSpellCasted(false))
1892 // melee attack spell casted at main hand attack only
1893 if (m_currentSpells
[CURRENT_MELEE_SPELL
] && attType
== BASE_ATTACK
)
1895 m_currentSpells
[CURRENT_MELEE_SPELL
]->cast();
1901 if (attType
== BASE_ATTACK
)
1902 hitInfo
= HITINFO_NORMALSWING2
;
1903 else if (attType
== OFF_ATTACK
)
1904 hitInfo
= HITINFO_LEFTSWING
;
1908 uint32 victimState
= VICTIMSTATE_NORMAL
;
1911 CleanDamage cleanDamage
= CleanDamage(0, BASE_ATTACK
, MELEE_HIT_NORMAL
);
1912 uint32 blocked_dmg
= 0;
1913 uint32 absorbed_dmg
= 0;
1914 uint32 resisted_dmg
= 0;
1916 if( pVictim
->IsImmunedToPhysicalDamage() )
1918 SendAttackStateUpdate (HITINFO_MISS
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, 0, 0, 0, VICTIMSTATE_IS_IMMUNE
, 0);
1922 DoAttackDamage (pVictim
, &damage
, &cleanDamage
, &blocked_dmg
, SPELL_SCHOOL_NORMAL
, &hitInfo
, &victimState
, &absorbed_dmg
, &resisted_dmg
, attType
);
1924 cleanDamage
.damage
+= blocked_dmg
;
1926 if (hitInfo
& HITINFO_MISS
)
1928 SendAttackStateUpdate (hitInfo
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
1932 SendAttackStateUpdate (hitInfo
, pVictim
, 1, SPELL_SCHOOL_NORMAL
, damage
, absorbed_dmg
, resisted_dmg
, victimState
, blocked_dmg
);
1934 if (damage
> (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
))
1935 damage
-= (absorbed_dmg
+ resisted_dmg
+ blocked_dmg
);
1939 DealDamage (pVictim
, damage
, &cleanDamage
, DIRECT_DAMAGE
, SPELL_SCHOOL_NORMAL
, NULL
, 0, true);
1941 if(GetTypeId() == TYPEID_PLAYER
&& pVictim
->isAlive())
1943 for(int i
= EQUIPMENT_SLOT_START
; i
< EQUIPMENT_SLOT_END
; i
++)
1944 ((Player
*)this)->CastItemCombatSpell(((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
,i
),pVictim
);
1948 if (GetTypeId() == TYPEID_PLAYER
)
1949 DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1950 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
1952 DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
1953 GetGUIDLow(), pVictim
->GetGUIDLow(), pVictim
->GetTypeId(), damage
, absorbed_dmg
, blocked_dmg
, resisted_dmg
);
1956 MeleeHitOutcome
Unit::RollPhysicalOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, SpellEntry
const *spellInfo
)
1958 // Miss chance based on melee
1959 int32 miss_chance
= (int32
)(MeleeMissChanceCalc(pVictim
));
1961 // Critical hit chance
1962 float crit_chance
= GetUnitCriticalChance(attType
);
1964 // Only players can have Talent&Spell bonuses
1965 if (GetTypeId() == TYPEID_PLAYER
)
1968 AuraList
const& mSpellCritSchool
= GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
);
1969 for(AuraList::const_iterator i
= mSpellCritSchool
.begin(); i
!= mSpellCritSchool
.end(); ++i
)
1970 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellInfo
->School
)) != 0)
1971 crit_chance
+= (*i
)->GetModifier()->m_amount
;
1974 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
1975 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
1976 crit_chance
+= (*i
)->GetModifier()->m_amount
;
1979 ((Player
*)this)->ApplySpellMod(spellInfo
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
1982 DEBUG_LOG("PHYSICAL OUTCOME: hit %u crit %f miss %u",m_modHitChance
,crit_chance
,miss_chance
);
1984 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
* 100 ), miss_chance
, m_modHitChance
);
1987 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
) const
1989 // This is only wrapper
1991 // Miss chance based on melee
1992 int32 miss_chance
= (int32
)(MeleeMissChanceCalc(pVictim
));
1994 // Critical hit chance
1995 float crit_chance
= GetUnitCriticalChance(attType
);
1998 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
1999 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
2000 crit_chance
+= (*i
)->GetModifier()->m_amount
;
2002 // Useful if want to specify crit & miss chances for melee, else it could be removed
2003 DEBUG_LOG("MELEE OUTCOME: hit %u crit %u miss %u", m_modHitChance
,crit_chance
,miss_chance
);
2004 return RollMeleeOutcomeAgainst(pVictim
, attType
, int32(crit_chance
* 100 ), miss_chance
, m_modHitChance
);
2007 MeleeHitOutcome
Unit::RollMeleeOutcomeAgainst (const Unit
*pVictim
, WeaponAttackType attType
, int32 crit_chance
, int32 miss_chance
, int32 hit_chance
) const
2009 int32 skillDiff
= GetWeaponSkillValue(attType
) - pVictim
->GetDefenseSkillValue();
2010 // bonus from skills is 0.04%
2011 int32 skillBonus
= skillDiff
* 4;
2012 int32 skillBonus2
= 4 * ( GetWeaponSkillValue(attType
) - pVictim
->GetPureDefenseSkillValue() );
2013 int32 sum
= 0, tmp
= 0;
2014 int32 roll
= urand (0, 10000);
2016 DEBUG_LOG ("RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus
);
2017 DEBUG_LOG ("RollMeleeOutcomeAgainst: rolled %d, +hit %d, dodge %u, parry %u, block %u, crit %u",
2018 roll
, hit_chance
, (uint32
)(pVictim
->GetUnitDodgeChance()*100), (uint32
)(pVictim
->GetUnitParryChance()*100),
2019 (uint32
)(pVictim
->GetUnitBlockChance()*100), crit_chance
);
2021 // dual wield has 24% base chance to miss instead of 5%, also
2022 // base miss rate is 5% and can't get higher than 60%
2024 // Inherit if passed
2025 tmp
= miss_chance
- skillBonus
;
2030 if (tmp
> 0 && roll
< (sum
+= tmp
))
2032 DEBUG_LOG ("RollMeleeOutcomeAgainst: MISS");
2033 return MELEE_HIT_MISS
;
2036 // always crit against a sitting target (except 0 crit chance)
2037 if( (pVictim
->GetTypeId() == TYPEID_PLAYER
) && crit_chance
> 0 &&
2038 (((Player
*)pVictim
)->getStandState() & (PLAYER_STATE_SLEEP
| PLAYER_STATE_SIT
2039 | PLAYER_STATE_SIT_CHAIR
2040 | PLAYER_STATE_SIT_LOW_CHAIR
2041 | PLAYER_STATE_SIT_MEDIUM_CHAIR
2042 | PLAYER_STATE_SIT_HIGH_CHAIR
)))
2044 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT (sitting victim)");
2045 return MELEE_HIT_CRIT
;
2048 // stunned target cannot dodge and this is check in GetUnitDodgeChance()
2049 tmp
= (int32
)(pVictim
->GetUnitDodgeChance()*100) - skillBonus2
;
2050 if (tmp
> 0 && roll
< (sum
+= tmp
))
2052 DEBUG_LOG ("RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum
-tmp
, sum
);
2053 return MELEE_HIT_DODGE
;
2058 // check if attack comes from behind
2059 if (!pVictim
->HasInArc(M_PI
,this))
2061 // ASSUME +10% crit from behind
2062 DEBUG_LOG ("RollMeleeOutcomeAgainst: attack came from behind.");
2067 // cannot parry or block attacks from behind, but can from forward
2068 tmp
= (int32
)(pVictim
->GetUnitParryChance()*100);
2069 if ( (tmp
> 0) // check if unit _can_ parry
2070 && ((tmp
-= skillBonus2
) > 0)
2071 && (roll
< (sum
+= tmp
)))
2073 DEBUG_LOG ("RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum
-tmp
, sum
);
2074 return MELEE_HIT_PARRY
;
2077 tmp
= (int32
)(pVictim
->GetUnitBlockChance()*100);
2078 if ( (tmp
> 0) // check if unit _can_ block
2079 && ((tmp
-= skillBonus2
) > 0)
2080 && (roll
< (sum
+= tmp
)))
2082 DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum
-tmp
, sum
);
2083 return MELEE_HIT_BLOCK
;
2087 // Resilience - reduce crit chance by x%
2088 modCrit
-= int32(pVictim
->m_modResilience
*100);
2091 tmp
= crit_chance
+ skillBonus
+ modCrit
;
2093 if (tmp
> 0 && roll
< (sum
+= tmp
))
2095 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum
-tmp
, sum
);
2096 return MELEE_HIT_CRIT
;
2099 // Max 40% chance to score a glancing blow against mobs that are higher level
2100 if( GetTypeId() == TYPEID_PLAYER
&& pVictim
->GetTypeId() != TYPEID_PLAYER
&& getLevel() < pVictim
->getLevel() )
2102 // cap possible value (with bonuses > max skill)
2103 int32 skill
= GetWeaponSkillValue(attType
);
2104 int32 maxskill
= GetMaxSkillValueForLevel();
2105 skill
= (skill
> maxskill
) ? maxskill
: skill
;
2107 tmp
= (10 + (pVictim
->GetDefenseSkillValue() - skill
)) * 100;
2108 tmp
= tmp
> 4000 ? 4000 : tmp
;
2109 if (roll
< (sum
+= tmp
))
2111 DEBUG_LOG ("RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum
-4000, sum
);
2112 return MELEE_HIT_GLANCING
;
2116 // mobs can score crushing blows if they're 3 or more levels above victim
2117 // or when their weapon skill is 15 or more above victim's defense skill
2118 tmp
= pVictim
->GetDefenseSkillValue();
2119 int32 tmpmax
= pVictim
->GetMaxSkillValueForLevel();
2120 // having defense above your maximum (from items, talents etc.) has no effect
2121 tmp
= tmp
> tmpmax
? tmpmax
: tmp
;
2122 // tmp = mob's level * 5 - player's current defense skill
2123 tmp
= GetMaxSkillValueForLevel() - tmp
;
2124 if (GetTypeId() != TYPEID_PLAYER
&& (tmp
>= 15))
2126 // add 2% chance per lacking skill point, min. is 15%
2127 tmp
= tmp
* 200 - 1500;
2128 if (roll
< (sum
+= tmp
))
2130 DEBUG_LOG ("RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum
-tmp
, sum
);
2131 return MELEE_HIT_CRUSHING
;
2135 DEBUG_LOG ("RollMeleeOutcomeAgainst: NORMAL");
2136 return MELEE_HIT_NORMAL
;
2139 uint32
Unit::CalculateDamage (WeaponAttackType attType
)
2141 float min_damage
, max_damage
;
2146 min_damage
= GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE
);
2147 max_damage
= GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE
);
2150 min_damage
= GetFloatValue(UNIT_FIELD_MINDAMAGE
);
2151 max_damage
= GetFloatValue(UNIT_FIELD_MAXDAMAGE
);
2154 min_damage
= GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE
);
2155 max_damage
= GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE
);
2159 if (min_damage
> max_damage
)
2161 std::swap(min_damage
,max_damage
);
2164 if(max_damage
== 0.0)
2167 return rand32((uint32
)min_damage
, (uint32
)max_damage
);
2170 void Unit::SendAttackStart(Unit
* pVictim
)
2172 if(GetTypeId()!=TYPEID_PLAYER
|| !pVictim
)
2175 WorldPacket
data( SMSG_ATTACKSTART
, 16 );
2177 data
<< pVictim
->GetGUID();
2179 ((Player
*)this)->SendMessageToSet(&data
, true);
2180 DEBUG_LOG( "WORLD: Sent SMSG_ATTACKSTART" );
2183 void Unit::SendAttackStop(Unit
* victim
)
2188 WorldPacket
data( SMSG_ATTACKSTOP
, (4+16) ); // we guess size
2189 data
.append(GetPackGUID());
2190 data
.append(victim
->GetPackGUID()); // can be 0x00...
2191 data
<< uint32(0); // can be 0x1
2192 SendMessageToSet(&data
, true);
2193 sLog
.outDetail("%s %u stopped attacking %s %u", (GetTypeId()==TYPEID_PLAYER
? "player" : "creature"), GetGUIDLow(), (victim
->GetTypeId()==TYPEID_PLAYER
? "player" : "creature"),victim
->GetGUIDLow());
2195 /*if(victim->GetTypeId() == TYPEID_UNIT)
2196 ((Creature*)victim)->AI().EnterEvadeMode(this);*/
2199 uint32
Unit::SpellMissChanceCalc(Unit
*pVictim
) const
2204 // PvP : PvE spell misschances per leveldif > 2
2205 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 700 : 1100;
2207 int32 leveldif
= pVictim
->getLevel() - getLevel();
2211 int32 misschance
= 400 - m_modSpellHitChance
*100;
2213 misschance
+= leveldif
* 100;
2215 misschance
+= (leveldif
- 2) * chance
;
2217 return misschance
< 100 ? 100 : misschance
;
2220 int32
Unit::MeleeMissChanceCalc(const Unit
*pVictim
) const
2225 // Base misschance 5%
2226 int32 misschance
= 500;
2228 // DualWield - Melee spells and physical dmg spells - 5% , white damage 24%
2229 if (haveOffhandWeapon())
2231 bool isNormal
= false;
2232 for (uint32 i
= CURRENT_FIRST_NON_MELEE_SPELL
; i
< CURRENT_MAX_SPELL
; i
++)
2234 if (m_currentSpells
[i
] && m_currentSpells
[i
]->m_spellInfo
->School
== SPELL_SCHOOL_NORMAL
)
2240 if (isNormal
|| m_currentSpells
[CURRENT_MELEE_SPELL
])
2250 // PvP : PvE melee misschances per leveldif > 2
2251 int32 chance
= pVictim
->GetTypeId() == TYPEID_PLAYER
? 500 : 700;
2253 int32 leveldif
= pVictim
->getLevel() - getLevel();
2258 misschance
+= leveldif
* 100 - m_modHitChance
*100;
2260 misschance
+= (leveldif
- 2) * chance
- m_modHitChance
*100;
2262 return misschance
> 6000 ? 6000 : misschance
;
2265 uint16
Unit::GetDefenseSkillValue() const
2267 if(GetTypeId() == TYPEID_PLAYER
)
2268 return ((Player
*)this)->GetSkillValue (SKILL_DEFENSE
);
2270 return GetUnitMeleeSkill();
2273 uint16
Unit::GetPureDefenseSkillValue() const
2275 if(GetTypeId() == TYPEID_PLAYER
)
2276 return ((Player
*)this)->GetPureSkillValue(SKILL_DEFENSE
);
2278 return GetUnitMeleeSkill();
2281 float Unit::GetUnitDodgeChance() const
2283 if(hasUnitState(UNIT_STAT_STUNDED
))
2285 return GetTypeId() == TYPEID_PLAYER
? GetFloatValue(PLAYER_DODGE_PERCENTAGE
) : 5;
2288 float Unit::GetUnitParryChance() const
2291 if(GetTypeId() == TYPEID_PLAYER
)
2293 Player
const* player
= (Player
const*)this;
2294 if(player
->CanParry() && player
->IsUseEquipedWeapon() )
2296 Item
*tmpitem
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
2297 if(!tmpitem
|| tmpitem
->IsBroken())
2298 tmpitem
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
2300 if(tmpitem
&& !tmpitem
->IsBroken() && (
2301 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPON
||
2302 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPONOFFHAND
||
2303 tmpitem
->GetProto()->InventoryType
== INVTYPE_WEAPONMAINHAND
||
2304 tmpitem
->GetProto()->InventoryType
== INVTYPE_2HWEAPON
))
2305 chance
= GetFloatValue(PLAYER_PARRY_PERCENTAGE
);
2308 else if(GetTypeId() == TYPEID_UNIT
)
2310 if(GetCreatureType() == CREATURE_TYPE_HUMANOID
)
2317 float Unit::GetUnitBlockChance() const
2320 if(GetTypeId() == TYPEID_PLAYER
)
2322 Item
*tmpitem
= ((Player
const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
2323 if(tmpitem
&& !tmpitem
->IsBroken() && tmpitem
->GetProto()->Block
)
2324 chance
= GetFloatValue(PLAYER_BLOCK_PERCENTAGE
);
2332 uint16
Unit::GetWeaponSkillValue (WeaponAttackType attType
) const
2334 if(GetTypeId() == TYPEID_PLAYER
)
2339 case BASE_ATTACK
: slot
= EQUIPMENT_SLOT_MAINHAND
; break;
2340 case OFF_ATTACK
: slot
= EQUIPMENT_SLOT_OFFHAND
; break;
2341 case RANGED_ATTACK
: slot
= EQUIPMENT_SLOT_RANGED
; break;
2345 Item
*item
= ((Player
*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0
, slot
);
2347 if(slot
!= EQUIPMENT_SLOT_MAINHAND
&& (!item
|| item
->IsBroken() ||
2348 item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((Player
*)this)->IsUseEquipedWeapon() ))
2352 uint32 skill
= item
&& !item
->IsBroken() && ((Player
*)this)->IsUseEquipedWeapon()
2353 ? item
->GetSkill() : SKILL_UNARMED
;
2354 return ((Player
*)this)->GetSkillValue (skill
);
2357 return GetUnitMeleeSkill();
2360 uint16
Unit::GetPureWeaponSkillValue (WeaponAttackType attType
) const
2362 if(GetTypeId() == TYPEID_PLAYER
)
2367 case BASE_ATTACK
: slot
= EQUIPMENT_SLOT_MAINHAND
; break;
2368 case OFF_ATTACK
: slot
= EQUIPMENT_SLOT_OFFHAND
; break;
2369 case RANGED_ATTACK
: slot
= EQUIPMENT_SLOT_RANGED
; break;
2373 Item
*item
= ((Player
*)this)->GetItemByPos (INVENTORY_SLOT_BAG_0
, slot
);
2375 if(slot
!= EQUIPMENT_SLOT_MAINHAND
&& (!item
|| item
->IsBroken() ||
2376 item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((Player
*)this)->IsUseEquipedWeapon() ))
2380 uint32 skill
= item
&& !item
->IsBroken() && ((Player
*)this)->IsUseEquipedWeapon()
2381 ? item
->GetSkill() : SKILL_UNARMED
;
2382 return ((Player
*)this)->GetPureSkillValue (skill
);
2385 return GetUnitMeleeSkill();
2388 void Unit::_UpdateSpells( uint32 time
)
2390 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
2391 _UpdateAutoRepeatSpell( time
);
2393 // remove finished spells from current pointers
2394 for (uint32 i
= 0; i
< CURRENT_MAX_SPELL
; i
++)
2396 if (m_currentSpells
[i
] && m_currentSpells
[i
]->getState() == SPELL_STATE_FINISHED
)
2398 m_currentSpells
[i
]->SetDeletable(true); // spell may be safely deleted now
2399 m_currentSpells
[i
] = NULL
; // remove pointer
2403 // TODO: Find a better way to prevent crash when multiple auras are removed.
2405 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
2407 (*i
).second
->SetUpdated(false);
2409 for (AuraMap::iterator i
= m_Auras
.begin(), next
; i
!= m_Auras
.end(); i
= next
)
2415 // prevent double update
2416 if ((*i
).second
->IsUpdated())
2418 (*i
).second
->SetUpdated(true);
2419 (*i
).second
->Update( time
);
2420 // several auras can be deleted due to update
2423 if (m_Auras
.empty()) break;
2424 next
= m_Auras
.begin();
2430 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
2434 if ( !(*i
).second
->GetAuraDuration() && !((*i
).second
->IsPermanent() || ((*i
).second
->IsPassive())) )
2449 if(!m_gameObj
.empty())
2451 std::list
<GameObject
*>::iterator ite1
, dnext1
;
2452 for (ite1
= m_gameObj
.begin(); ite1
!= m_gameObj
.end(); ite1
= dnext1
)
2455 //(*i)->Update( difftime );
2456 if( !(*ite1
)->isSpawned() )
2458 (*ite1
)->SetOwnerGUID(0);
2459 (*ite1
)->SetRespawnTime(0);
2461 dnext1
= m_gameObj
.erase(ite1
);
2469 void Unit::_UpdateAutoRepeatSpell( uint32 time
)
2471 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_FINISHED
)
2474 if( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->AttributesEx2
== 0x000020 && GetTypeId() == TYPEID_PLAYER
)
2476 // Auto Shot don't require ranged weapon cooldown at first cast, wand shoot does, so the 'FINISHED' state
2477 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2480 resetAttackTimer( RANGED_ATTACK
);
2485 if (m_AutoRepeatFirstCast
)
2487 // first cast only with recovery time (not less)
2488 if (getAttackTimer( RANGED_ATTACK
) < m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
)
2489 setAttackTimer( RANGED_ATTACK
, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
);
2490 m_AutoRepeatFirstCast
= false;
2494 // second or further casts
2495 resetAttackTimer( RANGED_ATTACK
);
2501 setAttackTimer( RANGED_ATTACK
, m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->RecoveryTime
);
2504 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_IDLE
);
2506 else if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_IDLE
&& isAttackReady(RANGED_ATTACK
) )
2508 // check if we can cast
2509 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CanCast() == 0)
2511 // check movement in player case
2512 if(GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->isMoving())
2514 // cancel wand shooting
2515 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2516 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2517 // ELSE delay auto-repeat ranged weapon until player movement stop
2520 // recheck range and req. items (ammo and gun, etc)
2521 if(m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CheckRange() == 0 && m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->CheckItems() == 0 )
2523 // check, if we are casting melee spell (it blocks autorepeat)
2524 if ( ! (m_currentSpells
[CURRENT_MELEE_SPELL
] &&
2525 (m_currentSpells
[CURRENT_MELEE_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2526 (m_currentSpells
[CURRENT_MELEE_SPELL
]->getState() != SPELL_STATE_DELAYED
)) )
2528 // check, if we are casting something else, if no then run autorepeat spell
2529 if (!IsNonMeleeSpellCasted(false, false, true))
2531 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_PREPARING
);
2532 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->ReSetTimer();
2538 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2543 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2546 else if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() == SPELL_STATE_PREPARING
)
2548 // check, if some other incomplete spell exists (including melee) or ranged attack is not ready
2549 if ( m_currentSpells
[CURRENT_MELEE_SPELL
] ||
2550 m_currentSpells
[CURRENT_GENERIC_SPELL
] ||
2551 m_currentSpells
[CURRENT_CHANNELED_SPELL
] ||
2552 !isAttackReady(RANGED_ATTACK
) )
2554 // some other spell is here or ranged attack is not ready, break us to idle state
2555 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->finish(false);
2556 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->setState(SPELL_STATE_IDLE
);
2561 void Unit::SetCurrentCastedSpell( Spell
* pSpell
)
2563 assert(pSpell
); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2565 uint32 CSpellType
= pSpell
->GetCurrentContainer();
2567 pSpell
->SetDeletable(false); // spell will not be deleted until gone from current pointers
2568 if (pSpell
== m_currentSpells
[CSpellType
]) return; // avoid breaking self
2570 // break same type spell if it is not delayed
2571 if ( m_currentSpells
[CSpellType
] &&
2572 m_currentSpells
[CSpellType
]->getState() != SPELL_STATE_DELAYED
)
2574 InterruptSpell(CSpellType
);
2577 // special breakage effects:
2580 case CURRENT_GENERIC_SPELL
:
2582 // generic spells always break channeled not delayed spells
2583 if ( m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
2584 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_DELAYED
)
2586 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2589 // autorepeat breaking
2590 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
2592 // break autorepeat if not Auto Shot
2593 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351)
2594 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2598 case CURRENT_CHANNELED_SPELL
:
2600 // channel spells always break generic and channeled spells
2601 InterruptSpell(CURRENT_GENERIC_SPELL
);
2602 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2604 // it also does break autorepeat if not Auto Shot
2605 if ( m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] &&
2606 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->m_spellInfo
->Category
== 351 )
2607 InterruptSpell(CURRENT_AUTOREPEAT_SPELL
);
2610 case CURRENT_AUTOREPEAT_SPELL
:
2612 // only Auto Shoot does not break anything
2613 if (pSpell
->m_spellInfo
->Category
== 351)
2615 // generic autorepeats break generic and channeled spells
2616 InterruptSpell(CURRENT_GENERIC_SPELL
);
2617 InterruptSpell(CURRENT_CHANNELED_SPELL
);
2621 // special action: set first cast flag for Auto Shoot
2622 m_AutoRepeatFirstCast
= true;
2628 // other spell types don't break anything now
2632 // current spell (if it is still here) may be safely deleted now
2633 if (m_currentSpells
[CSpellType
])
2634 m_currentSpells
[CSpellType
]->SetDeletable(true);
2636 // set new current spell
2637 m_currentSpells
[CSpellType
] = pSpell
;
2640 void Unit::InterruptSpell(uint32 spellType
)
2642 assert(spellType
< CURRENT_MAX_SPELL
);
2644 if(m_currentSpells
[spellType
])
2646 // send autorepeat cancel message for autorepeat spells
2647 if (spellType
== CURRENT_AUTOREPEAT_SPELL
)
2649 if(GetTypeId()==TYPEID_PLAYER
)
2650 ((Player
*)this)->SendAutoRepeatCancel();
2653 if (m_currentSpells
[spellType
]->getState() != SPELL_STATE_FINISHED
)
2654 m_currentSpells
[spellType
]->cancel();
2655 m_currentSpells
[spellType
]->SetDeletable(true);
2656 m_currentSpells
[spellType
] = NULL
;
2660 bool Unit::IsNonMeleeSpellCasted(bool withDelayed
, bool skipChanneled
, bool skipAutorepeat
)
2662 // We don't do loop here to explicitly show that melee spell is excluded.
2663 // Maybe later some special spells will be excluded too.
2665 // generic spells are casted when they are not finished and not delayed
2666 if ( m_currentSpells
[CURRENT_GENERIC_SPELL
] &&
2667 (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2668 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2671 // channeled spells may be delayed, but they are still considered casted
2672 else if ( !skipChanneled
&& m_currentSpells
[CURRENT_CHANNELED_SPELL
] &&
2673 (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
) )
2676 // autorepeat spells may be finished or delayed, but they are still considered casted
2677 else if ( !skipAutorepeat
&& m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] )
2683 void Unit::InterruptNonMeleeSpells(bool withDelayed
)
2685 // generic spells are interrupted if they are not finished or delayed
2686 if (m_currentSpells
[CURRENT_GENERIC_SPELL
])
2688 if ( (m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2689 (withDelayed
|| m_currentSpells
[CURRENT_GENERIC_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2690 m_currentSpells
[CURRENT_GENERIC_SPELL
]->cancel();
2691 m_currentSpells
[CURRENT_GENERIC_SPELL
]->SetDeletable(true);
2692 m_currentSpells
[CURRENT_GENERIC_SPELL
] = NULL
;
2695 // autorepeat spells are interrupted if they are not finished or delayed
2696 if (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
])
2698 // send disable autorepeat packet in any case
2699 if(GetTypeId()==TYPEID_PLAYER
)
2700 ((Player
*)this)->SendAutoRepeatCancel();
2702 if ( (m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_FINISHED
) &&
2703 (withDelayed
|| m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->getState() != SPELL_STATE_DELAYED
) )
2704 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->cancel();
2705 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
]->SetDeletable(true);
2706 m_currentSpells
[CURRENT_AUTOREPEAT_SPELL
] = NULL
;
2709 // channeled spells are interrupted if they are not finished, even if they are delayed
2710 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
])
2712 if (m_currentSpells
[CURRENT_CHANNELED_SPELL
]->getState() != SPELL_STATE_FINISHED
)
2713 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->cancel();
2714 m_currentSpells
[CURRENT_CHANNELED_SPELL
]->SetDeletable(true);
2715 m_currentSpells
[CURRENT_CHANNELED_SPELL
] = NULL
;
2719 bool Unit::isInFront(Unit
const* target
, float radius
) const
2721 return IsWithinDistInMap(target
, radius
) && HasInArc( M_PI
, target
);
2724 void Unit::SetInFront(Unit
const* target
)
2726 SetOrientation(GetAngle(target
));
2729 bool Unit::isInAccessablePlaceFor(Creature
* c
) const
2732 return c
->isCanSwimOrFly();
2734 return c
->isCanWalkOrFly();
2737 bool Unit::IsInWater() const
2739 return MapManager::Instance().GetMap(GetMapId(), this)->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ());
2742 bool Unit::IsUnderWater() const
2744 return MapManager::Instance().GetMap(GetMapId(), this)->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ());
2747 void Unit::DeMorph()
2749 SetUInt32Value(UNIT_FIELD_DISPLAYID
, GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID
));
2752 long Unit::GetTotalAuraModifier(uint32 ModifierID
) const
2754 uint32 modifier
= 0;
2756 AuraList
const& mTotalAuraList
= GetAurasByType(ModifierID
);
2757 for(AuraList::const_iterator i
= mTotalAuraList
.begin();i
!= mTotalAuraList
.end(); ++i
)
2758 modifier
+= (*i
)->GetModifier()->m_amount
;
2763 bool Unit::AddAura(Aura
*Aur
, bool uniq
)
2765 // ghost spell check
2766 if (!isAlive() && !(Aur
->GetSpellProto()->Id
== 20584 || Aur
->GetSpellProto()->Id
== 8326))
2772 if(Aur
->GetTarget() != this)
2774 sLog
.outError("Aura (spell %u eff %u) add to aura list of %s (lowguid: %u) but Aura target is %s (lowguid: %u)",
2775 Aur
->GetId(),Aur
->GetEffIndex(),(GetTypeId()==TYPEID_PLAYER
?"player":"creature"),GetGUIDLow(),
2776 (Aur
->GetTarget()->GetTypeId()==TYPEID_PLAYER
?"player":"creature"),Aur
->GetTarget()->GetGUIDLow());
2781 AuraMap::iterator i
= m_Auras
.find( spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()) );
2783 // take out same spell
2784 if (i
!= m_Auras
.end())
2786 /*(*i).second->SetAuraDuration(Aur->GetAuraDuration());
2787 if ((*i).second->GetTarget())
2788 if ((*i).second->GetTarget()->GetTypeId() == TYPEID_PLAYER )
2789 (*i).second->UpdateAuraDuration();
2792 // passive and persistent auras can stack with themselves any number of times
2793 if (!Aur
->IsPassive() && !Aur
->IsPersistent() && m_Auras
.count(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex())) >= Aur
->GetSpellProto()->StackAmount
)
2797 // passive auras stack with all (except passive spell proc auras)
2798 if ((!Aur
->IsPassive() || !IsPassiveStackableSpell(Aur
->GetId())) &&
2799 !(Aur
->GetSpellProto()->Id
== 20584 || Aur
->GetSpellProto()->Id
== 8326))
2801 if (!RemoveNoStackAurasDueToAura(Aur
))
2804 return false; // couldnt remove conflicting aura with higher rank
2808 // adding linked auras
2809 // add the shapeshift aura's boosts
2810 if(Aur
->GetModifier()->m_auraname
== SPELL_AURA_MOD_SHAPESHIFT
)
2811 Aur
->HandleShapeshiftBoosts(true);
2814 m_Auras
.insert(AuraMap::value_type(spellEffectPair(Aur
->GetId(), Aur
->GetEffIndex()), Aur
));
2815 if (Aur
->GetModifier()->m_auraname
< TOTAL_AURAS
)
2817 m_modAuras
[Aur
->GetModifier()->m_auraname
].push_back(Aur
);
2818 m_AuraModifiers
[Aur
->GetModifier()->m_auraname
] += (Aur
->GetModifier()->m_amount
);
2821 if (IsSingleTarget(Aur
->GetId()) && Aur
->GetTarget() && Aur
->GetSpellProto())
2823 if(Unit
* caster
= Aur
->GetCaster())
2825 AuraList
& scAuras
= caster
->GetSingleCastAuras();
2826 AuraList::iterator itr
, next
;
2827 for (itr
= scAuras
.begin(); itr
!= scAuras
.end(); itr
= next
)
2831 if ((*itr
)->GetTarget() != Aur
->GetTarget() &&
2832 (*itr
)->GetSpellProto()->Category
== Aur
->GetSpellProto()->Category
&&
2833 (*itr
)->GetSpellProto()->SpellIconID
== Aur
->GetSpellProto()->SpellIconID
&&
2834 (*itr
)->GetSpellProto()->SpellVisual
== Aur
->GetSpellProto()->SpellVisual
&&
2835 (*itr
)->GetSpellProto()->Attributes
== Aur
->GetSpellProto()->Attributes
&&
2836 (*itr
)->GetSpellProto()->AttributesEx
== Aur
->GetSpellProto()->AttributesEx
&&
2837 (*itr
)->GetSpellProto()->AttributesExEx
== Aur
->GetSpellProto()->AttributesExEx
)
2839 (*itr
)->GetTarget()->RemoveAura((*itr
)->GetId(), (*itr
)->GetEffIndex());
2843 next
= scAuras
.begin();
2846 scAuras
.push_back(Aur
);
2852 void Unit::RemoveRankAurasDueToSpell(uint32 spellId
)
2854 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
2857 AuraMap::iterator i
,next
;
2858 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
2862 uint32 i_spellId
= (*i
).second
->GetId();
2863 if((*i
).second
&& i_spellId
&& i_spellId
!= spellId
)
2865 if(objmgr
.IsRankSpellDueToSpell(spellInfo
,i_spellId
))
2867 RemoveAurasDueToSpell(i_spellId
);
2869 if( m_Auras
.empty() )
2872 next
= m_Auras
.begin();
2878 bool Unit::RemoveNoStackAurasDueToAura(Aura
*Aur
)
2883 SpellEntry
const* spellProto
= Aur
->GetSpellProto();
2887 uint32 spellId
= Aur
->GetId();
2888 uint32 effIndex
= Aur
->GetEffIndex();
2889 bool is_sec
= IsSpellSingleEffectPerCaster(spellId
);
2890 AuraMap::iterator i
,next
;
2891 for (i
= m_Auras
.begin(); i
!= m_Auras
.end(); i
= next
)
2895 if (!(*i
).second
) continue;
2897 if (!(*i
).second
->GetSpellProto())
2900 uint32 i_spellId
= (*i
).second
->GetId();
2902 if(IsPassiveSpell(i_spellId
))
2904 if(IsPassiveStackableSpell(i_spellId
))
2907 // passive non-stackable spells not stackable only with another rank of same spell
2908 if (!objmgr
.IsRankSpellDueToSpell(Aur
->GetSpellProto(), i_spellId
))
2912 uint32 i_effIndex
= (*i
).second
->GetEffIndex();
2914 if(i_spellId
== spellId
) continue;
2916 bool is_triggered_by_spell
= false;
2917 // prevent triggered aura of removing aura that triggered it
2918 for(int j
= 0; j
< 3; ++j
)
2919 if ((*i
).second
->GetSpellProto()->EffectTriggerSpell
[j
] == spellProto
->Id
)
2920 is_triggered_by_spell
= true;
2921 if (is_triggered_by_spell
) continue;
2923 // prevent remove dummy triggered spells at next effect aura add
2924 for(int j
= 0; j
< 3; ++j
)
2926 switch(spellProto
->Effect
[j
])
2928 case SPELL_EFFECT_DUMMY
:
2931 case 5420: if(i_spellId
==34123) is_triggered_by_spell
= true; break;
2935 if(is_triggered_by_spell
)
2938 switch(spellProto
->EffectApplyAuraName
[j
])
2940 case SPELL_AURA_MOD_SHAPESHIFT
:
2943 case 33891: if(i_spellId
==5420 || i_spellId
==34123) is_triggered_by_spell
= true; break;
2949 if(!is_triggered_by_spell
)
2951 bool sec_match
= false;
2952 bool is_i_sec
= IsSpellSingleEffectPerCaster(i_spellId
);
2953 if( is_sec
&& is_i_sec
)
2954 if (Aur
->GetCasterGUID() == (*i
).second
->GetCasterGUID())
2955 if (GetSpellSpecific(spellId
) == GetSpellSpecific(i_spellId
))
2957 if( sec_match
|| objmgr
.IsNoStackSpellDueToSpell(spellId
, i_spellId
) && !is_sec
&& !is_i_sec
)
2959 // if sec_match this isn't always true, needs to be rechecked
2960 if (objmgr
.IsRankSpellDueToSpell(Aur
->GetSpellProto(), i_spellId
))
2961 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
2962 return false; // cannot remove higher rank
2964 RemoveAurasDueToSpell(i_spellId
);
2966 if( m_Auras
.empty() )
2969 next
= m_Auras
.begin();
2971 else // Potions stack aura by aura
2972 if (Aur
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_POTION
&&
2973 (*i
).second
->GetSpellProto()->SpellFamilyName
== SPELLFAMILY_POTION
)
2975 if (IsNoStackAuraDueToAura(spellId
, effIndex
, i_spellId
, i_effIndex
))
2977 if(CompareAuraRanks(spellId
, effIndex
, i_spellId
, i_effIndex
) < 0)
2978 return false; // cannot remove higher rank
2989 void Unit::RemoveFirstAuraByDispel(uint32 dispel_type
, Unit
*pCaster
)
2991 AuraMap::iterator i
;
2992 for (i
= m_Auras
.begin(); i
!= m_Auras
.end();)
2994 if ((*i
).second
&& (*i
).second
->GetSpellProto()->Dispel
== dispel_type
)
2996 SpellEntry
const* spellInfo
= (*i
).second
->GetSpellProto();
2997 uint32 eff
= (*i
).second
->GetEffIndex();
2999 if(dispel_type
== 1)
3001 bool positive
= true;
3003 if(!IsPositiveTarget(spellInfo
->EffectImplicitTargetA
[eff
],spellInfo
->EffectImplicitTargetB
[eff
]))
3006 positive
= (spellInfo
->AttributesEx
& (1<<7))==0;
3008 if(positive
&& IsFriendlyTo(pCaster
)) // PBW
3022 void Unit::RemoveAreaAurasByOthers(uint64 guid
)
3025 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end();)
3027 if (i
->second
&& i
->second
->IsAreaAura())
3029 uint64 casterGuid
= i
->second
->GetCasterGUID();
3030 uint64 targetGuid
= i
->second
->GetTarget()->GetGUID();
3031 // if area aura cast by someone else or by the specified caster
3032 if (casterGuid
== guid
|| (guid
== 0 && casterGuid
!= targetGuid
))
3034 for (j
= 0; j
< 4; j
++)
3035 if (m_TotemSlot
[j
] == casterGuid
)
3037 // and not by one of my totems
3051 void Unit::RemoveAura(uint32 spellId
, uint32 effindex
)
3053 AuraMap::iterator iter
;
3054 while((iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
))) != m_Auras
.end())
3058 void Unit::RemoveAurasDueToSpell(uint32 spellId
)
3060 for (int i
= 0; i
< 3; ++i
)
3061 RemoveAura(spellId
,i
);
3064 void Unit::RemoveAurasDueToItem(Item
* castItem
)
3066 for (AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end(); )
3068 if (iter
->second
->GetCastItemGUID() == castItem
->GetGUID())
3075 void Unit::RemoveAura(AuraMap::iterator
&i
, bool onDeath
)
3077 if (IsSingleTarget((*i
).second
->GetId()))
3079 if(Unit
* caster
= (*i
).second
->GetCaster())
3081 AuraList
& scAuras
= caster
->GetSingleCastAuras();
3082 scAuras
.remove((*i
).second
);
3085 sLog
.outError("Unit::RemoveAura: cannot remove the single cast aura (SpellId: %u Effect: %u) from the caster, potential crash!",(*i
).second
->GetId(),(*i
).second
->GetEffIndex());
3087 // remove aura from party members when the caster turns off the aura
3088 if((*i
).second
->IsAreaAura())
3090 Unit
*i_target
= (*i
).second
->GetTarget();
3091 if((*i
).second
->GetCasterGUID() == i_target
->GetGUID())
3093 Unit
* i_caster
= i_target
;
3096 Group
*pGroup
= NULL
;
3097 Player
*pGroupOf
= NULL
;
3098 if (i_caster
->GetTypeId() == TYPEID_PLAYER
)
3100 pGroupOf
= (Player
*)i_caster
;
3101 pGroup
= pGroupOf
->GetGroup();
3103 else if(((Creature
*)i_caster
)->isTotem() || ((Creature
*)i_caster
)->isPet() || i_caster
->isCharmed())
3105 owner
= i_caster
->GetCharmerOrOwner();
3106 if (owner
&& owner
->GetTypeId() == TYPEID_PLAYER
)
3108 pGroupOf
= (Player
*)owner
;
3109 pGroup
= pGroupOf
->GetGroup();
3113 //float radius = GetRadius(sSpellRadiusStore.LookupEntry((*i).second->GetSpellProto()->EffectRadiusIndex[(*i).second->GetEffIndex()]));
3114 if(pGroup
&& pGroupOf
)
3116 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
3118 Player
* Target
= itr
->getSource();
3119 if(!Target
|| !pGroup
->SameSubGroup(pGroupOf
, Target
))
3122 if(Target
->GetGUID() == i_caster
->GetGUID())
3124 Aura
*t_aura
= Target
->GetAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3126 if (t_aura
->GetCasterGUID() == i_caster
->GetGUID())
3127 Target
->RemoveAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3132 Aura
*t_aura
= owner
->GetAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3134 if (t_aura
->GetCasterGUID() == i_caster
->GetGUID())
3135 owner
->RemoveAura((*i
).second
->GetId(), (*i
).second
->GetEffIndex());
3139 if ((*i
).second
->GetModifier()->m_auraname
< TOTAL_AURAS
)
3141 m_AuraModifiers
[(*i
).second
->GetModifier()->m_auraname
] -= ((*i
).second
->GetModifier()->m_amount
);
3142 m_modAuras
[(*i
).second
->GetModifier()->m_auraname
].remove((*i
).second
);
3144 (*i
).second
->SetRemoveOnDeath(onDeath
);
3146 // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order)
3147 Aura
* Aur
= i
->second
;
3149 DiminishingMechanics mech
= DIMINISHING_NONE
;
3150 if(Aur
->GetSpellProto()->Mechanic
)
3152 mech
= Unit::Mechanic2DiminishingMechanics(Aur
->GetSpellProto()->Mechanic
);
3153 if(mech
== DIMINISHING_MECHANIC_STUN
|| GetTypeId() == TYPEID_PLAYER
&& mech
!= DIMINISHING_NONE
)
3154 UpdateDiminishingTime(mech
);
3157 // must remove before removing from list (its remove dependent auras and _i_ is only safe iterator value
3158 // remove the shapeshift aura's boosts
3159 if(Aur
->GetModifier()->m_auraname
== SPELL_AURA_MOD_SHAPESHIFT
)
3160 Aur
->HandleShapeshiftBoosts(false);
3163 m_removedAuras
++; // internal count used by unit update
3168 // only way correctly remove all auras from list
3169 if( m_Auras
.empty() )
3172 i
= m_Auras
.begin();
3175 bool Unit::SetAurDuration(uint32 spellId
, uint32 effindex
,uint32 duration
)
3177 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3178 if (iter
!= m_Auras
.end())
3180 (*iter
).second
->SetAuraDuration(duration
);
3181 (*iter
).second
->UpdateAuraDuration();
3187 uint32
Unit::GetAurDuration(uint32 spellId
, uint32 effindex
)
3189 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3190 if (iter
!= m_Auras
.end())
3192 return (*iter
).second
->GetAuraDuration();
3197 void Unit::RemoveAllAuras()
3199 while (!m_Auras
.empty())
3201 AuraMap::iterator iter
= m_Auras
.begin();
3206 void Unit::RemoveAllAurasOnDeath()
3208 // used just after dieing to remove all visible auras
3209 // and disable the mods for the passive ones
3210 for(AuraMap::iterator iter
= m_Auras
.begin(); iter
!= m_Auras
.end();)
3212 if (!iter
->second
->IsPassive())
3213 RemoveAura(iter
, true);
3219 void Unit::DelayAura(uint32 spellId
, uint32 effindex
, int32 delaytime
)
3221 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3222 if (iter
!= m_Auras
.end())
3224 if (iter
->second
->GetAuraDuration() < delaytime
)
3225 iter
->second
->SetAuraDuration(0);
3227 iter
->second
->SetAuraDuration(iter
->second
->GetAuraDuration() - delaytime
);
3228 iter
->second
->UpdateAuraDuration();
3229 sLog
.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter
->second
->GetModifier()->m_auraname
, GetGUIDLow(), iter
->second
->GetAuraDuration());
3233 void Unit::_RemoveAllAuraMods()
3235 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3237 (*i
).second
->ApplyModifier(false);
3241 void Unit::_ApplyAllAuraMods()
3243 for (AuraMap::iterator i
= m_Auras
.begin(); i
!= m_Auras
.end(); ++i
)
3245 (*i
).second
->ApplyModifier(true);
3250 /*void Unit::_UpdateAura()
3252 if(GetTypeId() != TYPEID_PLAYER || !m_Auras)
3255 Player* pThis = (Player*)this;
3260 pGroup = objmgr.GetGroupByLeader(pThis->GetGroupLeader());
3262 if(!SetAffDuration(m_Auras->GetId(),this,6000))
3269 for(uint32 i=0;i<pGroup->GetMembersCount();i++)
3271 pGroupGuy = ObjectAccessor::Instance().FindPlayer(pGroup->GetMemberGUID(i));
3275 if(pGroupGuy->GetGUID() == GetGUID())
3278 (GetPositionX()-pGroupGuy->GetPositionX())*(GetPositionX()-pGroupGuy->GetPositionX())
3279 +(GetPositionY()-pGroupGuy->GetPositionY())*(GetPositionY()-pGroupGuy->GetPositionY())
3280 +(GetPositionZ()-pGroupGuy->GetPositionZ())*(GetPositionZ()-pGroupGuy->GetPositionZ())
3283 if(!pGroupGuy->SetAffDuration(m_Auras->GetId(),this,6000))
3284 pGroupGuy->AddAura(m_Auras);
3288 if(m_removeAuraTimer == 0)
3290 printf("remove aura from %u\n", pGroupGuy->GetGUID());
3291 pGroupGuy->RemoveAura(m_Auras->GetId());
3296 if(m_removeAuraTimer > 0)
3297 m_removeAuraTimer -= 1;
3299 m_removeAuraTimer = 4;
3302 Aura
* Unit::GetAura(uint32 spellId
, uint32 effindex
)
3304 AuraMap::iterator iter
= m_Auras
.find(spellEffectPair(spellId
, effindex
));
3305 if (iter
!= m_Auras
.end())
3306 return iter
->second
;
3310 void Unit::AddDynObject(DynamicObject
* dynObj
)
3312 m_dynObjGUIDs
.push_back(dynObj
->GetGUID());
3315 void Unit::RemoveDynObject(uint32 spellid
)
3317 if(m_dynObjGUIDs
.empty())
3319 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
3321 DynamicObject
* dynObj
= ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
3324 i
= m_dynObjGUIDs
.erase(i
);
3326 else if(spellid
== 0 || dynObj
->GetSpellId() == spellid
)
3329 i
= m_dynObjGUIDs
.erase(i
);
3336 DynamicObject
* Unit::GetDynObject(uint32 spellId
, uint32 effIndex
)
3338 for (DynObjectGUIDs::iterator i
= m_dynObjGUIDs
.begin(); i
!= m_dynObjGUIDs
.end();)
3340 DynamicObject
* dynObj
= ObjectAccessor::Instance().GetDynamicObject(*this,*m_dynObjGUIDs
.begin());
3343 i
= m_dynObjGUIDs
.erase(i
);
3347 if (dynObj
->GetSpellId() == spellId
&& dynObj
->GetEffIndex() == effIndex
)
3354 void Unit::AddGameObject(GameObject
* gameObj
)
3356 assert(gameObj
&& gameObj
->GetOwnerGUID()==0);
3357 m_gameObj
.push_back(gameObj
);
3358 gameObj
->SetOwnerGUID(GetGUID());
3361 void Unit::RemoveGameObject(GameObject
* gameObj
, bool del
)
3363 assert(gameObj
&& gameObj
->GetOwnerGUID()==GetGUID());
3364 gameObj
->SetOwnerGUID(0);
3365 m_gameObj
.remove(gameObj
);
3368 gameObj
->SetRespawnTime(0);
3373 void Unit::RemoveGameObject(uint32 spellid
, bool del
)
3375 if(m_gameObj
.empty())
3377 std::list
<GameObject
*>::iterator i
, next
;
3378 for (i
= m_gameObj
.begin(); i
!= m_gameObj
.end(); i
= next
)
3381 if(spellid
== 0 || (*i
)->GetSpellId() == spellid
)
3383 (*i
)->SetOwnerGUID(0);
3386 (*i
)->SetRespawnTime(0);
3390 next
= m_gameObj
.erase(i
);
3397 void Unit::SendSpellNonMeleeDamageLog(Unit
*target
,uint32 SpellID
,uint32 Damage
, SpellSchools DamageType
,uint32 AbsorbedDamage
, uint32 Resist
,bool PhysicalDamage
, uint32 Blocked
, bool CriticalHit
)
3399 WorldPacket
data(SMSG_SPELLNONMELEEDAMAGELOG
, (16+31)); // we guess size
3400 data
.append(target
->GetPackGUID());
3401 data
.append(GetPackGUID());
3402 data
<< uint32(SpellID
);
3403 data
<< uint32(Damage
-AbsorbedDamage
-Resist
-Blocked
);
3404 data
<< uint8(DamageType
); //damagetype
3405 data
<< uint32(AbsorbedDamage
); //AbsorbedDamage
3406 data
<< uint32(Resist
); //resist
3407 data
<< (uint8
)PhysicalDamage
;
3409 data
<< uint32(Blocked
); //blocked
3410 data
<< uint8(CriticalHit
? 2 : 0); //seen 0x05 also...
3412 SendMessageToSet( &data
, true );
3415 void Unit::SendAttackStateUpdate(uint32 HitInfo
, Unit
*target
, uint8 SwingType
, SpellSchools DamageType
, uint32 Damage
, uint32 AbsorbDamage
, uint32 Resist
, uint32 TargetState
, uint32 BlockedAmount
)
3417 sLog
.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
3419 WorldPacket
data(SMSG_ATTACKERSTATEUPDATE
, (16+45)); // we guess size
3420 data
<< (uint32
)HitInfo
;
3421 data
.append(GetPackGUID());
3422 data
.append(target
->GetPackGUID());
3423 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3425 data
<< (uint8
)SwingType
;
3426 data
<< (uint32
)DamageType
;
3429 data
<< (float)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3430 // still need to double check damaga
3431 data
<< (uint32
)(Damage
-AbsorbDamage
-Resist
-BlockedAmount
);
3432 data
<< (uint32
)AbsorbDamage
;
3433 data
<< (uint32
)Resist
;
3434 data
<< (uint32
)TargetState
;
3436 if( AbsorbDamage
== 0 ) //also 0x3E8 = 0x3E8, check when that happens
3442 data
<< (uint32
)BlockedAmount
;
3444 SendMessageToSet( &data
, true );
3447 void Unit::ProcDamageAndSpell(Unit
*pVictim
, uint32 procAttacker
, uint32 procVictim
, uint32 damage
, SpellEntry
const *procSpell
, bool isTriggeredSpell
, WeaponAttackType attType
)
3449 sLog
.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker
, procVictim
);
3451 sLog
.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell
->Id
, (isTriggeredSpell
?"(triggered)":""));
3453 // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities
3454 // not assign for spell proc triggered spell to prevent infinity (or unexpacted 2-3 times) melee damage spell proc call with melee damage effect
3455 // That is the question though if it's fully correct
3456 if(procSpell
&& !isTriggeredSpell
)
3458 if(procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_MELEE
)
3460 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_MELEE
;
3461 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_MELEE
;
3462 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_MELEE
;
3463 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_MELEE
;
3464 attType
= BASE_ATTACK
; // Melee abilities are assumed to be dealt with mainhand weapon
3466 else if (procSpell
->DmgClass
== SPELL_DAMAGE_CLASS_RANGED
)
3468 if(procAttacker
& PROC_FLAG_HIT_SPELL
) procAttacker
|= PROC_FLAG_HIT_RANGED
;
3469 if(procAttacker
& PROC_FLAG_CRIT_SPELL
) procAttacker
|= PROC_FLAG_CRIT_RANGED
;
3470 if(procVictim
& PROC_FLAG_STRUCK_SPELL
) procVictim
|= PROC_FLAG_STRUCK_RANGED
;
3471 if(procVictim
& PROC_FLAG_STRUCK_CRIT_SPELL
) procVictim
|= PROC_FLAG_STRUCK_CRIT_RANGED
;
3472 attType
= RANGED_ATTACK
;
3475 if(damage
&& (procVictim
& (PROC_FLAG_STRUCK_MELEE
|PROC_FLAG_STRUCK_RANGED
|PROC_FLAG_STRUCK_SPELL
)))
3476 procVictim
|= (PROC_FLAG_TAKE_DAMAGE
|PROC_FLAG_TOUCH
);
3478 // Not much to do if no flags are set.
3481 ProcDamageAndSpellFor(false,pVictim
,procAttacker
,attackerProcAuraTypes
,attType
, procSpell
, damage
);
3484 // Now go on with a victim's events'n'auras
3485 // Not much to do if no flags are set or there is no victim
3486 if(pVictim
&& pVictim
->isAlive() && procVictim
)
3488 pVictim
->ProcDamageAndSpellFor(true,this,procVictim
,victimProcAuraTypes
,attType
,procSpell
, damage
);
3492 void Unit::CastMeleeProcDamageAndSpell(Unit
* pVictim
, uint32 damage
, WeaponAttackType attType
, MeleeHitOutcome outcome
, SpellEntry
const *spellCasted
, bool isTriggeredSpell
)
3497 uint32 procAttacker
= PROC_FLAG_NONE
;
3498 uint32 procVictim
= PROC_FLAG_NONE
;
3502 case MELEE_HIT_MISS
:
3503 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3505 procAttacker
= PROC_FLAG_MISS
;
3508 case MELEE_HIT_CRIT
:
3509 if(spellCasted
&& attType
== BASE_ATTACK
)
3511 procAttacker
|= PROC_FLAG_CRIT_SPELL
;
3512 procVictim
|= PROC_FLAG_STRUCK_CRIT_SPELL
;
3514 else if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3516 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
3517 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
3521 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
3522 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
3525 case MELEE_HIT_PARRY
:
3526 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
3527 procVictim
= PROC_FLAG_PARRY
;
3529 case MELEE_HIT_BLOCK
:
3530 procAttacker
= PROC_FLAG_TARGET_BLOCK
;
3531 procVictim
= PROC_FLAG_BLOCK
;
3533 case MELEE_HIT_DODGE
:
3534 procAttacker
= PROC_FLAG_TARGET_DODGE_OR_PARRY
;
3535 procVictim
= PROC_FLAG_DODGE
;
3537 case MELEE_HIT_CRUSHING
:
3538 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3540 procAttacker
= PROC_FLAG_HIT_MELEE
| PROC_FLAG_CRIT_MELEE
;
3541 procVictim
= PROC_FLAG_STRUCK_MELEE
| PROC_FLAG_STRUCK_CRIT_MELEE
;
3545 procAttacker
= PROC_FLAG_HIT_RANGED
| PROC_FLAG_CRIT_RANGED
;
3546 procVictim
= PROC_FLAG_STRUCK_RANGED
| PROC_FLAG_STRUCK_CRIT_RANGED
;
3550 if(attType
== BASE_ATTACK
|| attType
== OFF_ATTACK
)
3552 procAttacker
= PROC_FLAG_HIT_MELEE
;
3553 procVictim
= PROC_FLAG_STRUCK_MELEE
;
3557 procAttacker
= PROC_FLAG_HIT_RANGED
;
3558 procVictim
= PROC_FLAG_STRUCK_RANGED
;
3564 procVictim
|= PROC_FLAG_TAKE_DAMAGE
;
3566 if(procAttacker
!= PROC_FLAG_NONE
|| procVictim
!= PROC_FLAG_NONE
)
3567 ProcDamageAndSpell(pVictim
, procAttacker
, procVictim
, damage
, spellCasted
, isTriggeredSpell
, attType
);
3570 void Unit::HandleDummyAuraProc(Unit
*pVictim
, SpellEntry
const *dummySpell
, uint32 effIndex
, uint32 damage
, Aura
* triggredByAura
, SpellEntry
const * procSpell
, uint32 procFlag
)
3572 switch(dummySpell
->Id
)
3581 if(!pVictim
|| !pVictim
->isAlive())
3584 int32 igniteDotBasePoints0
;
3586 switch (dummySpell
->Id
)
3588 case 11119: igniteDotBasePoints0
=int32(0.04f
*damage
)-1; break;
3589 case 11120: igniteDotBasePoints0
=int32(0.08f
*damage
)-1; break;
3590 case 12846: igniteDotBasePoints0
=int32(0.12f
*damage
)-1; break;
3591 case 12847: igniteDotBasePoints0
=int32(0.16f
*damage
)-1; break;
3592 case 12848: igniteDotBasePoints0
=int32(0.20f
*damage
)-1; break;
3594 sLog
.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)",dummySpell
->Id
);
3597 CastCustomSpell(pVictim
, 12654, &igniteDotBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3604 CastSpell(this, 28682, true, NULL
, triggredByAura
);
3605 if (!(procFlag
& PROC_FLAG_CRIT_SPELL
)) //no crit
3606 triggredByAura
->m_procCharges
+= 1; //-> reincrease procCharge count since it was decreased before
3607 else if (triggredByAura
->m_procCharges
== 0) //no more charges left and crit
3608 RemoveAurasDueToSpell(28682); //-> remove Combustion auras
3615 CastSpell(this, 17941, true, NULL
, triggredByAura
);
3621 if(!pVictim
|| !pVictim
->isAlive())
3624 if(triggredByAura
->GetCasterGUID() == pVictim
->GetGUID())
3626 //VEHeal has a BaseDice of 0, so no decrement needed
3627 int32 VEHealBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100;
3628 pVictim
->CastCustomSpell(pVictim
, 15290, &VEHealBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3636 if(!pVictim
|| !pVictim
->isAlive())
3639 // return damage % to attacker but < 50% own total health
3640 uint32 backDamage
= triggredByAura
->GetModifier()->m_amount
*damage
/100;
3641 if(backDamage
> GetMaxHealth()/2)
3642 backDamage
= GetMaxHealth()/2;
3644 int32 YYDamageBasePoints0
= backDamage
-1;
3645 CastCustomSpell(pVictim
, 25997, &YYDamageBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3660 // we assume lightning bolt and chain lightning are generic (not channeled/autorepeat) spells
3661 if(!pVictim
|| !m_currentSpells
[CURRENT_GENERIC_SPELL
])
3664 // remove cooldown from first cast
3665 if(GetTypeId()==TYPEID_PLAYER
)
3666 ((Player
*)this)->RemoveSpellCooldown(procSpell
->Id
);
3667 // prepare cast as triggered spell (this need for correct targets selection after not finished currently cast)
3668 m_currentSpells
[CURRENT_GENERIC_SPELL
]->AddTriggeredSpell(procSpell
);
3678 // if healed by another unit (pVictim)
3681 int32 SAHealBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100-1;
3682 CastCustomSpell(this, 31786, &SAHealBasePoints0
, NULL
, NULL
, true, NULL
, triggredByAura
);
3688 // Shadowflame (item set effect)
3691 if(GetTypeId() != TYPEID_PLAYER
|| !pVictim
|| !pVictim
->isAlive())
3694 Item
* castItem
= ((Player
*)this)->GetItemByGuid(triggredByAura
->GetCastItemGUID());
3698 CastSpell(pVictim
,37379,true,castItem
,triggredByAura
);
3701 // Shadowflame Hellfire (item set effect)
3704 if(GetTypeId() != TYPEID_PLAYER
|| !pVictim
|| !pVictim
->isAlive())
3707 Item
* castItem
= ((Player
*)this)->GetItemByGuid(triggredByAura
->GetCastItemGUID());
3711 CastSpell(pVictim
,37378,true,castItem
,triggredByAura
);
3718 switch(dummySpell
->SpellFamilyName
)
3720 case SPELLFAMILY_SHAMAN
:
3721 if(dummySpell
->SpellFamilyFlags
==0x40000000000LL
)
3723 int32 HealBasePoints0
= dummySpell
->EffectBasePoints
[0];
3724 CastCustomSpell(this,379,&HealBasePoints0
,NULL
,NULL
,true,NULL
,triggredByAura
);
3732 // Non SpellID checks
3733 switch(dummySpell
->SpellIconID
)
3735 // Master of Elements
3741 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_MAGE
)
3744 int32 MEManaCostSave
= procSpell
->manaCost
* triggredByAura
->GetModifier()->m_amount
/100;
3745 if(MEManaCostSave
<= 0)
3747 int32 MEManaRestoreBasePoints0
= MEManaCostSave
-1;
3748 CastCustomSpell(this,29077,&MEManaRestoreBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
3755 if(!pVictim
|| !pVictim
->isAlive())
3758 if(triggredByAura
->GetCasterGUID() == pVictim
->GetGUID())
3760 int32 VTEnergizeBasePoints0
= triggredByAura
->GetModifier()->m_amount
*damage
/100 - 1;
3761 pVictim
->CastCustomSpell(pVictim
,34919,&VTEnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
3771 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
)
3774 // only rogue's finishing moves (maybe need additional checks)
3775 if( procSpell
->SpellFamilyName
!=SPELLFAMILY_ROGUE
||
3776 (procSpell
->SpellFamilyFlags
& (0x40000 | 0x80000 | 0x100000 | 0x200000 | 0x800000000LL
| 0x20000)) == 0)
3779 int32 QREnegyCostSave
= procSpell
->manaCost
* triggredByAura
->GetModifier()->m_amount
/100;
3780 if(QREnegyCostSave
<= 0)
3782 int32 QREnergizeBasePoints0
= QREnegyCostSave
-1;
3783 CastCustomSpell(this,31663,&QREnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
3787 // Thrill of the Hunt
3793 if(dummySpell
->SpellFamilyName
!=SPELLFAMILY_HUNTER
)
3796 int32 THManaCostSave
= procSpell
->manaCost
* 40/100;
3797 if(THManaCostSave
<= 0)
3799 int32 THEnergizeBasePoints0
= THManaCostSave
-1;
3800 CastCustomSpell(this,34720,&THEnergizeBasePoints0
,NULL
,NULL
,true,NULL
, triggredByAura
);
3807 void Unit::HandleProcTriggerSpell(Unit
*pVictim
, uint32 damage
, Aura
* triggeredByAura
, SpellEntry
const *procSpell
, uint32 procFlags
)
3809 SpellEntry
const* auraSpellInfo
= triggeredByAura
->GetSpellProto();
3811 switch(auraSpellInfo
->SpellIconID
)
3815 switch(auraSpellInfo
->SpellFamilyName
)
3817 case SPELLFAMILY_SHAMAN
:
3819 //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
3820 if(auraSpellInfo
->SpellFamilyFlags
==0x00000400)
3822 if(!pVictim
|| !pVictim
->isAlive())
3826 switch(triggeredByAura
->GetSpellProto()->Id
)
3829 case 324: spell
= 26364; break;
3831 case 325: spell
= 26365; break;
3833 case 905: spell
= 26366; break;
3835 case 945: spell
= 26367; break;
3837 case 8134: spell
= 26369; break;
3839 case 10431: spell
= 26370; break;
3841 case 10432: spell
= 26363; break;
3843 case 25469: spell
= 26371; break;
3845 case 25472: spell
= 26372; break;
3847 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura
->GetSpellProto()->Id
);
3850 CastSpell(pVictim
, spell
, true, NULL
, triggeredByAura
);
3855 case SPELLFAMILY_PRIEST
:
3857 // Priest's "Shadowguard"
3858 if(auraSpellInfo
->SpellFamilyFlags
==0x100080000000LL
)
3860 if(!pVictim
|| !pVictim
->isAlive())
3864 switch(triggeredByAura
->GetSpellProto()->Id
)
3867 case 18137: spell
= 28377; break;
3869 case 19308: spell
= 28378; break;
3871 case 19309: spell
= 28379; break;
3873 case 19310: spell
= 28380; break;
3875 case 19311: spell
= 28381; break;
3877 case 19312: spell
= 28382; break;
3879 case 25477: spell
= 28385; break;
3881 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura
->GetSpellProto()->Id
);
3884 CastSpell(pVictim
, spell
, true, NULL
, triggeredByAura
);
3894 //Mana Surge (Shaman T1 bonus)
3899 int32 manaSurgeSpellBasePoints0
= procSpell
->manaCost
* 35/100;
3900 CastCustomSpell(this, 23571, &manaSurgeSpellBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
3905 //Improved Drain Soul
3907 Unit::AuraList
const& mAddFlatModifier
= GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER
);
3908 for(Unit::AuraList::const_iterator i
= mAddFlatModifier
.begin(); i
!= mAddFlatModifier
.end(); ++i
)
3910 if ((*i
)->GetModifier()->m_miscvalue
== SPELLMOD_CHANCE_OF_SUCCESS
&& (*i
)->GetSpellProto()->SpellIconID
== 113)
3912 int32 impDrainSoulBasePoints0
= (*i
)->GetSpellProto()->EffectBasePoints
[2] * GetMaxPower(POWER_MANA
) / 100;
3913 CastCustomSpell(this, 18371, &impDrainSoulBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
3920 switch(auraSpellInfo
->EffectTriggerSpell
[0])
3928 SpellEntry
const *originalSpell
= procSpell
;
3930 // in case HShock procspell is triggered spell but we need mana cost of original casted spell
3931 if(procSpell
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& procSpell
->SpellFamilyFlags
== 0x00200000)
3933 uint32 originalSpellId
= 0;
3934 switch(procSpell
->Id
)
3936 case 25914: originalSpellId
= 20473; break;
3937 case 25913: originalSpellId
= 20929; break;
3938 case 25903: originalSpellId
= 20930; break;
3939 case 27175: originalSpellId
= 27174; break;
3940 case 33074: originalSpellId
= 33072; break;
3942 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell
->Id
);
3945 SpellEntry
const *HSSpell
= sSpellStore
.LookupEntry(originalSpellId
);
3948 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but used in HShock",originalSpellId
);
3951 originalSpell
= HSSpell
;
3954 // percent stored in effect 1 (class scripts) base points
3955 int32 percent
= auraSpellInfo
->EffectBasePoints
[1]+1;
3957 // BasePoints = val -1 not required (EffectBaseDice==0)
3958 int32 ILManaSpellBasePoints0
= originalSpell
->manaCost
*percent
/100;
3959 CastCustomSpell(this, 20272, &ILManaSpellBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
3967 //Improved Leader of the Pack
3969 if (triggeredByAura
->GetModifier()->m_amount
== 0)
3971 int32 improvedLotPBasePoints0
= triggeredByAura
->GetModifier()->m_amount
* GetMaxHealth() / 100 - 1;
3972 CastCustomSpell(this, 34299, &improvedLotPBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
3973 if (GetTypeId() == TYPEID_PLAYER
)
3974 ((Player
*)this)->AddSpellCooldown(34299,0,time(NULL
) + 6);
3979 if(!pVictim
|| !pVictim
->isAlive())
3984 switch (triggeredByAura
->GetSpellProto()->Id
)
3993 if (roll_chance_f(chance
))
3994 CastSpell(pVictim
, 18093, true, NULL
, triggeredByAura
);
4000 uint32 EffectId
= 0;
4001 switch (triggeredByAura
->GetSpellProto()->Id
)
4003 case 27811: EffectId
= 27813; break;
4004 case 27815: EffectId
= 27817; break;
4005 case 27816: EffectId
= 27818; break;
4007 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura
->GetSpellProto()->Id
);
4011 int32 heal_amount
= damage
* triggeredByAura
->GetModifier()->m_amount
/ 100;
4012 int32 BRHealBasePoints0
= heal_amount
/3-1;
4013 CastCustomSpell(this, EffectId
, &BRHealBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4018 //Effects: 30029(Rank 1), 30031(Rank 2), 30032(Rank 3)
4019 //Check EffectTriggerSpell[1] to determine correct effect id
4020 //CastSpell(this, triggredByAura->GetSpellProto()->EffectTriggerSpell[1], true, NULL, triggredByAura);
4025 //Effects: 31616, 39301
4027 /*float HealthRatio = GetHealth() / GetMaxHealth();
4028 float HealthRatioBefore = (GetHealth() + damage) / GetMaxHealth();
4029 if (HealthRatio < 0.3 && HealthRatioBefore >= 0.3)
4031 SpellEntry const *NGHealTemplate = sSpellStore.LookupEntry(31616);
4032 SpellEntry NGHeal = *NGHealTemplate;
4033 NGHeal.EffectBasePoints[0] = triggredByAura->GetModifier()->m_amount * GetMaxHealth() / 100;
4034 CastSpell(this, &NGHeal, true, NULL, triggredByAura);
4035 if (pVictim && pVictim->isAlive())
4036 CastSpell(pVictim, 39301, true, NULL, triggredByAura);
4037 if (GetTypeId() == TYPEID_PLAYER)
4039 ((Player*)this)->AddSpellCooldown(31616,0,time(NULL) + 5);
4040 ((Player*)this)->AddSpellCooldown(39301,0,time(NULL) + 5);
4047 CastSpell(this, 31643, true, NULL
, triggeredByAura
);
4051 // custom check for proc spell
4052 switch(auraSpellInfo
->Id
)
4054 // Lightning Capacitor
4057 if(!pVictim
|| !pVictim
->isAlive())
4061 CastSpell(this, 37658, true, NULL
, triggeredByAura
);
4065 AuraList
const& dummyAura
= GetAurasByType(SPELL_AURA_DUMMY
);
4066 for(AuraList::const_iterator itr
= dummyAura
.begin(); itr
!= dummyAura
.end(); ++itr
)
4067 if((*itr
)->GetId()==37658)
4070 // release at 3 aura in stack
4073 RemoveAurasDueToSpell(37658);
4074 CastSpell(pVictim
, 37661, true, NULL
, triggeredByAura
);
4080 // standard non-dummy case
4081 uint32 trigger_spell_id
= auraSpellInfo
->EffectTriggerSpell
[triggeredByAura
->GetEffIndex()];
4082 if(!trigger_spell_id
)
4084 sLog
.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo
->Id
,triggeredByAura
->GetEffIndex());
4088 // but with dummy basepoints or other customs
4089 switch(trigger_spell_id
)
4091 // Shamanistic Rage triggered spell
4094 int32 SRBasePoints0
= int32(GetTotalAttackPowerValue(BASE_ATTACK
)*triggeredByAura
->GetModifier()->m_amount
/100) -1;
4095 CastCustomSpell(this, 30824, &SRBasePoints0
, NULL
, NULL
, true, NULL
, triggeredByAura
);
4098 // Backlash triggered spell
4101 // need set custom cooldown
4102 if(isAlive() && GetTypeId()==TYPEID_PLAYER
&& !((Player
*)this)->HasSpellCooldown(34936))
4104 CastSpell(this,trigger_spell_id
,true,NULL
,triggeredByAura
);
4105 ((Player
*)this)->AddSpellCooldown(34936,0,time(NULL
)+8);
4112 if(IsPositiveSpell(trigger_spell_id
) && !(procFlags
& PROC_FLAG_HEAL
))
4113 CastSpell(this,trigger_spell_id
,true,NULL
,triggeredByAura
);
4114 else if(pVictim
&& pVictim
->isAlive())
4115 CastSpell(pVictim
,trigger_spell_id
,true,NULL
,triggeredByAura
);
4118 void Unit::setPowerType(Powers new_powertype
)
4120 uint32 tem_bytes_0
= GetUInt32Value(UNIT_FIELD_BYTES_0
);
4121 SetUInt32Value(UNIT_FIELD_BYTES_0
,((tem_bytes_0
<<8)>>8) + (uint32(new_powertype
)<<24));
4123 if (GetTypeId() == TYPEID_PLAYER
)
4124 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE
);
4126 switch(new_powertype
)
4132 SetMaxPower(POWER_RAGE
,GetCreatePowers(POWER_RAGE
));
4133 SetPower( POWER_RAGE
,0);
4136 SetMaxPower(POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
4137 SetPower( POWER_FOCUS
,GetCreatePowers(POWER_FOCUS
));
4140 SetMaxPower(POWER_ENERGY
,GetCreatePowers(POWER_ENERGY
));
4141 SetPower( POWER_ENERGY
,0);
4143 case POWER_HAPPINESS
:
4144 SetMaxPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
4145 SetPower(POWER_HAPPINESS
,GetCreatePowers(POWER_HAPPINESS
));
4150 FactionTemplateEntry
const* Unit::getFactionTemplateEntry() const
4152 FactionTemplateEntry
const* entry
= sFactionTemplateStore
.LookupEntry(getFaction());
4155 static uint64 guid
= 0; // prevent repeating spam same faction problem
4157 if(GetGUID() != guid
)
4159 if(GetTypeId() == TYPEID_PLAYER
)
4160 sLog
.outError("Player %s have invalid faction (faction template id) #%u", ((Player
*)this)->GetName(), getFaction());
4162 sLog
.outError("Creature (template id: %u) have invalid faction (faction template id) #%u", ((Creature
*)this)->GetCreatureInfo()->Entry
, getFaction());
4169 bool Unit::IsHostileTo(Unit
const* unit
) const
4171 // always non-hostile to self
4175 // always hostile to enemy
4176 if(getVictim()==unit
|| unit
->getVictim()==this)
4179 // test pet/charm masters instead pers/charmeds
4180 Unit
const* testerOwner
= GetCharmerOrOwner();
4181 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
4183 // always hostile to owner's enemy
4184 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
4187 // always hostile to enemy owner
4188 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
4191 // always hostile to owner of owner's enemy
4192 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
4195 Unit
const* tester
= testerOwner
? testerOwner
: this;
4196 Unit
const* target
= targetOwner
? targetOwner
: unit
;
4198 // special cases (Duel, etc)
4199 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
4202 if(((Player
const*)tester
)->duel
&& ((Player
const*)tester
)->duel
->opponent
== target
&& ((Player
const*)tester
)->duel
->startTime
!= 0)
4206 // Green/Blue (can't attack)
4207 if(((Player
*)tester
)->GetTeam()==((Player
*)target
)->GetTeam())
4210 // Red (can attack) if true, Blue/Yellow (can't attack) in another case
4211 return ((Player
*)tester
)->IsPvP() && ((Player
*)target
)->IsPvP();
4214 // faction base cases
4215 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
4216 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
4217 if(!tester_faction
|| !target_faction
)
4220 // PvC forced reaction and reputation case
4221 if(tester
->GetTypeId()==TYPEID_PLAYER
)
4224 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
4225 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
4227 return forceItr
->second
<= REP_HOSTILE
;
4230 // apply reputation state
4231 FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
);
4232 if(raw_target_faction
&& raw_target_faction
->reputationListID
>=0 )
4234 if(((Player
*)tester
)->IsFactionAtWar(raw_target_faction
))
4238 // CvP forced reaction and reputation case
4239 else if(target
->GetTypeId()==TYPEID_PLAYER
)
4242 ForcedReactions::const_iterator forceItr
= ((Player
*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
4243 if(forceItr
!=((Player
*)target
)->m_forcedReactions
.end())
4245 return forceItr
->second
<= REP_HOSTILE
;
4248 // apply reputation state
4249 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
4250 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
4252 return ((Player
*)target
)->GetReputationRank(raw_tester_faction
) <= REP_HOSTILE
;
4256 // common faction based case (CvC,PvC,CvP)
4257 return tester_faction
->IsHostileTo(*target_faction
);
4260 bool Unit::IsFriendlyTo(Unit
const* unit
) const
4262 // always friendly to self
4266 // always non-friendly to enemy
4267 if(getVictim()==unit
|| unit
->getVictim()==this)
4270 // test pet/charm masters instead pers/charmeds
4271 Unit
const* testerOwner
= GetCharmerOrOwner();
4272 Unit
const* targetOwner
= unit
->GetCharmerOrOwner();
4274 // always non-friendly to owner's enemy
4275 if(testerOwner
&& (testerOwner
->getVictim()==unit
|| unit
->getVictim()==testerOwner
))
4278 // always non-friendly to enemy owner
4279 if(targetOwner
&& (getVictim()==targetOwner
|| targetOwner
->getVictim()==this))
4282 // always non-friendly to owner of owner's enemy
4283 if(testerOwner
&& targetOwner
&& (testerOwner
->getVictim()==targetOwner
|| targetOwner
->getVictim()==testerOwner
))
4286 Unit
const* tester
= testerOwner
? testerOwner
: this;
4287 Unit
const* target
= targetOwner
? targetOwner
: unit
;
4289 // special cases (Duel)
4290 if(tester
->GetTypeId()==TYPEID_PLAYER
&& target
->GetTypeId()==TYPEID_PLAYER
)
4293 if(((Player
const*)tester
)->duel
&& ((Player
const*)tester
)->duel
->opponent
== target
&& ((Player
const*)tester
)->duel
->startTime
!= 0)
4297 // Green/Blue (non-attackable)
4298 if(((Player
*)tester
)->GetTeam()==((Player
*)target
)->GetTeam())
4301 // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
4302 return !((Player
*)target
)->IsPvP();
4305 // faction base cases
4306 FactionTemplateEntry
const*tester_faction
= tester
->getFactionTemplateEntry();
4307 FactionTemplateEntry
const*target_faction
= target
->getFactionTemplateEntry();
4308 if(!tester_faction
|| !target_faction
)
4311 // PvC forced reaction and reputation case
4312 if(tester
->GetTypeId()==TYPEID_PLAYER
)
4315 ForcedReactions::const_iterator forceItr
= ((Player
*)tester
)->m_forcedReactions
.find(target_faction
->faction
);
4316 if(forceItr
!=((Player
*)tester
)->m_forcedReactions
.end())
4318 return forceItr
->second
>= REP_FRIENDLY
;
4321 // apply reputation state
4322 FactionEntry
const* raw_target_faction
= sFactionStore
.LookupEntry(target_faction
->faction
);
4323 if(raw_target_faction
&& raw_target_faction
->reputationListID
>=0 )
4325 if(((Player
*)tester
)->IsFactionAtWar(raw_target_faction
))
4329 // CvP forced reaction and reputation case
4330 else if(target
->GetTypeId()==TYPEID_PLAYER
)
4333 ForcedReactions::const_iterator forceItr
= ((Player
*)target
)->m_forcedReactions
.find(tester_faction
->faction
);
4334 if(forceItr
!=((Player
*)target
)->m_forcedReactions
.end())
4336 return forceItr
->second
>= REP_FRIENDLY
;
4339 // apply reputation state
4340 FactionEntry
const* raw_tester_faction
= sFactionStore
.LookupEntry(tester_faction
->faction
);
4341 if(raw_tester_faction
&& raw_tester_faction
->reputationListID
>=0 )
4343 return ((Player
*)target
)->GetReputationRank(raw_tester_faction
) >= REP_FRIENDLY
;
4347 // common faction based case (CvC,PvC,CvP)
4348 return tester_faction
->IsFriendlyTo(*target_faction
);
4351 bool Unit::IsHostileToPlayers() const
4353 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
4357 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
4358 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
4361 return my_faction
->IsHostileToPlayers();
4364 bool Unit::IsNeutralToAll() const
4366 FactionTemplateEntry
const* my_faction
= getFactionTemplateEntry();
4370 FactionEntry
const* raw_faction
= sFactionStore
.LookupEntry(my_faction
->faction
);
4371 if(raw_faction
&& raw_faction
->reputationListID
>=0 )
4374 return my_faction
->IsNeutralToAll();
4377 bool Unit::Attack(Unit
*victim
, bool playerMeleeAttack
)
4379 if(!victim
|| victim
== this)
4382 // player don't must attack in mount state
4383 if(GetTypeId()==TYPEID_PLAYER
&& IsMounted())
4386 // anyone don't must attack GM in GM-mode
4387 if(victim
->GetTypeId()==TYPEID_PLAYER
&& ((Player
*)victim
)->isGameMaster())
4392 if (m_attacking
== victim
)
4398 SetUInt64Value(UNIT_FIELD_TARGET
, victim
->GetGUID());
4400 addUnitState(UNIT_STAT_ATTACKING
);
4402 m_attacking
= victim
;
4403 m_attacking
->_addAttacker(this);
4405 if(m_attacking
->GetTypeId()==TYPEID_UNIT
&& ((Creature
*)m_attacking
)->AI())
4406 ((Creature
*)m_attacking
)->AI()->AttackedBy(this);
4408 if( GetTypeId()==TYPEID_UNIT
&& !(((Creature
*)this)->isPet() || isCharmed()) )
4410 ((Creature
*)this)->CallAssistence();
4412 //if(!isAttackReady(BASE_ATTACK))
4413 //resetAttackTimer(BASE_ATTACK);
4415 // delay offhand weapon attack to next attack time
4416 if(haveOffhandWeapon())
4417 resetAttackTimer(OFF_ATTACK
);
4419 if(playerMeleeAttack
)
4420 SendAttackStart(victim
);
4425 bool Unit::AttackStop()
4430 Unit
* victim
= m_attacking
;
4432 m_attacking
->_removeAttacker(this);
4436 SetUInt64Value(UNIT_FIELD_TARGET
, 0);
4438 clearUnitState(UNIT_STAT_ATTACKING
);
4440 InterruptSpell(CURRENT_MELEE_SPELL
);
4442 if( GetTypeId()==TYPEID_UNIT
)
4444 // reset call assistance
4445 ((Creature
*)this)->SetNoCallAssistence(false);
4448 SendAttackStop(victim
);
4453 bool Unit::isAttackingPlayer() const
4457 if(getVictim()->GetTypeId() == TYPEID_PLAYER
)
4460 if(getVictim()->GetOwnerGUID() && GUID_HIPART(getVictim()->GetOwnerGUID())==HIGHGUID_PLAYER
)
4464 Pet
* pet
= GetPet();
4465 if(pet
&& pet
->isAttackingPlayer())
4468 Unit
* charmed
= GetCharm();
4469 if(charmed
&& charmed
->isAttackingPlayer())
4472 for (int8 i
= 0; i
< 4; i
++)
4476 Creature
*totem
= ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot
[i
]);
4477 if(totem
&& totem
->isAttackingPlayer())
4485 void Unit::RemoveAllAttackers()
4487 while (m_attackers
.size() != 0)
4489 AttackerSet::iterator iter
= m_attackers
.begin();
4490 if(!(*iter
)->AttackStop())
4492 sLog
.outError("WORLD: Unit has an attacker that isnt attacking it!");
4493 m_attackers
.erase(iter
);
4498 void Unit::ModifyAuraState(uint32 flag
, bool apply
)
4502 if (!HasFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1)))
4504 SetFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
4505 if(GetTypeId() == TYPEID_PLAYER
)
4507 const PlayerSpellMap
& sp_list
= ((Player
*)this)->GetSpellMap();
4508 for (PlayerSpellMap::const_iterator itr
= sp_list
.begin(); itr
!= sp_list
.end(); ++itr
)
4510 if(itr
->second
->state
== PLAYERSPELL_REMOVED
) continue;
4511 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(itr
->first
);
4512 if (!spellInfo
|| !IsPassiveSpell(itr
->first
)) continue;
4513 if (spellInfo
->CasterAuraState
== flag
)
4514 CastSpell(this, itr
->first
, true, NULL
);
4521 if (HasFlag(UNIT_FIELD_AURASTATE
,1<<(flag
-1)))
4523 RemoveFlag(UNIT_FIELD_AURASTATE
, 1<<(flag
-1));
4524 Unit::AuraMap
& tAuras
= GetAuras();
4525 for (Unit::AuraMap::iterator itr
= tAuras
.begin(); itr
!= tAuras
.end();)
4527 if ((*itr
).second
->GetSpellProto()->CasterAuraState
== flag
)
4536 Unit
*Unit::GetOwner() const
4538 uint64 ownerid
= GetOwnerGUID();
4541 return ObjectAccessor::Instance().GetUnit(*this, ownerid
);
4544 Unit
*Unit::GetCharmer() const
4546 uint64 charmerid
= GetCharmerGUID();
4549 return ObjectAccessor::Instance().GetUnit(*this, charmerid
);
4552 Pet
* Unit::GetPet() const
4554 uint64 pet_guid
= GetPetGUID();
4557 Pet
* pet
= ObjectAccessor::Instance().GetPet(pet_guid
);
4560 sLog
.outError("Unit::GetPet: Pet %u not exist.",GUID_LOPART(pet_guid
));
4561 const_cast<Unit
*>(this)->SetPet(0);
4570 Unit
* Unit::GetCharm() const
4572 uint64 charm_guid
= GetCharmGUID();
4575 Unit
* pet
= ObjectAccessor::Instance().GetUnit(*this, charm_guid
);
4578 sLog
.outError("Unit::GetCharm: Charmed creature %u not exist.",GUID_LOPART(charm_guid
));
4579 const_cast<Unit
*>(this)->SetCharm(0);
4587 void Unit::SetPet(Pet
* pet
)
4589 SetUInt64Value(UNIT_FIELD_SUMMON
,pet
? pet
->GetGUID() : 0);
4593 for(int i
= 0; i
< MAX_MOVE_TYPE
; ++i
)
4595 pet
->SetSpeed(UnitMoveType(i
),m_speed_rate
[i
],true);
4600 void Unit::SetCharm(Unit
* charmed
)
4602 SetUInt64Value(UNIT_FIELD_CHARM
,charmed
? charmed
->GetGUID() : 0);
4605 void Unit::UnsummonAllTotems()
4607 for (int8 i
= 0; i
< 4; ++i
)
4612 Creature
*OldTotem
= ObjectAccessor::Instance().GetCreature(*this, m_TotemSlot
[i
]);
4613 if (OldTotem
&& OldTotem
->isTotem())
4614 ((Totem
*)OldTotem
)->UnSummon();
4618 void Unit::SendHealSpellOnPlayer(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
, bool critical
)
4621 WorldPacket
data(SMSG_HEALSPELL_ON_PLAYER_OBSOLETE
, (8+8+4+4+1));
4622 data
.append(pVictim
->GetPackGUID());
4623 data
.append(GetPackGUID());
4626 data
<< uint8(critical
? 1 : 0);
4627 SendMessageToSet(&data
, true);
4630 void Unit::SendHealSpellOnPlayerPet(Unit
*pVictim
, uint32 SpellID
, uint32 Damage
,Powers powertype
, bool critical
)
4632 WorldPacket
data(SMSG_HEALSPELL_ON_PLAYERS_PET_OBSOLETE
, (8+8+4+4+4+1));
4633 data
.append(pVictim
->GetPackGUID());
4634 data
.append(GetPackGUID());
4636 data
<< uint32(powertype
);
4638 data
<< uint8(critical
? 1 : 0);
4639 SendMessageToSet(&data
, true);
4642 uint32
Unit::SpellDamageBonus(Unit
*pVictim
, SpellEntry
const *spellProto
, uint32 pdamage
, DamageEffectType damagetype
)
4644 if(!spellProto
|| !pVictim
|| damagetype
==DIRECT_DAMAGE
)
4647 if(pVictim
->IsImmunedToSpellDamage(spellProto
))
4650 uint32 creatureTypeMask
= GetCreatureTypeMask();
4653 uint32 CastingTime
= GetCastTime(sCastTimesStore
.LookupEntry(spellProto
->CastingTimeIndex
));
4654 if (CastingTime
> 7000) CastingTime
= 7000; // Plus Damage efficient maximum 200% ( 7.0 seconds )
4655 if (CastingTime
< 1500) CastingTime
= 1500;
4657 // Taken/Done fixed damage bonus auras
4658 int32 DoneAdvertisedBenefit
= 0;
4659 int32 TakenAdvertisedBenefit
= 0;
4661 // ..done (for creature type by mask) in taken
4662 AuraList
const& mDamageDoneCreature
= GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
4663 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
4664 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
4665 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4668 AuraList
const& mDamageDone
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE
);
4669 for(AuraList::const_iterator i
= mDamageDone
.begin();i
!= mDamageDone
.end(); ++i
)
4670 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 &&
4671 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
4672 // -1 == any item class (not wand then)
4673 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
4674 // 0 == any inventory type (not wand then)
4675 DoneAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4677 if (GetTypeId() == TYPEID_PLAYER
)
4679 // Damage bonus of spirit
4680 AuraList
const& mDamageDonebySpi
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_SPIRIT
);
4681 for(AuraList::const_iterator i
= mDamageDonebySpi
.begin();i
!= mDamageDonebySpi
.end(); ++i
)
4682 if((*i
)->GetModifier()->m_miscvalue
& 1 << spellProto
->School
)
4683 DoneAdvertisedBenefit
+= int32(GetStat(STAT_SPIRIT
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
4685 // ... and intellect
4686 AuraList
const& mDamageDonebyInt
= GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT
);
4687 for(AuraList::const_iterator i
= mDamageDonebyInt
.begin();i
!= mDamageDonebyInt
.end(); ++i
)
4688 if ((*i
)->GetModifier()->m_miscvalue
& 1 << spellProto
->School
)
4689 DoneAdvertisedBenefit
+= int32(GetStat(STAT_INTELLECT
) * (*i
)->GetModifier()->m_amount
/ 100.0f
);
4693 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
4694 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
4695 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
4696 TakenAdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4698 // Damage over Time spells bonus calculation
4699 float DotFactor
= 1.0f
;
4700 if(damagetype
== DOT
)
4703 uint32 DotDuration
= GetDuration(spellProto
);
4707 if(DotDuration
> 30000) DotDuration
= 30000;
4708 DotFactor
= DotDuration
/ 15000.0f
;
4710 for(int j
= 0; j
< 3; j
++)
4711 if(spellProto
->Effect
[j
] == 6) x
= j
;
4713 if(spellProto
->EffectAmplitude
[x
] != 0)
4714 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
4717 DoneAdvertisedBenefit
/= DotTicks
;
4718 TakenAdvertisedBenefit
/= DotTicks
;
4723 // Taken/Done total percent damage auras
4724 float DoneTotalMod
= 1.0f
;
4725 float TakenTotalMod
= 1.0f
;
4728 AuraList
const& mModDamagePercentDone
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
);
4729 for(AuraList::const_iterator i
= mModDamagePercentDone
.begin(); i
!= mModDamagePercentDone
.end(); ++i
)
4731 if( ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 &&
4732 (*i
)->GetSpellProto()->EquippedItemClass
== -1 &&
4733 // -1 == any item class (not wand then)
4734 (*i
)->GetSpellProto()->EquippedItemInventoryTypeMask
== 0 )
4735 // 0 == any inventory type (not wand then)
4737 DoneTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
4742 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
4743 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
4744 if( ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0 )
4745 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
4749 if(spellProto
->SpellVisual
== 1225 && spellProto
->SpellIconID
== 208)
4751 CastingTime
= 2800; // 80% from +shadow damage
4752 DoneTotalMod
= 1.0f
;
4753 TakenTotalMod
= 1.0f
;
4756 if(spellProto
->SpellVisual
== 827 && spellProto
->SpellIconID
== 154 && GetPet())
4758 CastingTime
= 3360; // 96% from +shadow damage
4759 DoneTotalMod
= 1.0f
;
4760 TakenTotalMod
= 1.0f
;
4763 if(spellProto
->Id
== 30455)
4765 CastingTime
/= 3.0f
; // applied 1/3 bonuses in case generic target
4766 if(pVictim
->isFrozen()) // and compensate this for frozen target.
4767 TakenTotalMod
*= 3.0f
;
4771 float LvlPenalty
= 0.0f
;
4772 if(spellProto
->spellLevel
< 20)
4773 LvlPenalty
= (20.0f
- (float)(spellProto
->spellLevel
)) * 3.75f
;
4774 float LvlFactor
= ((float)(spellProto
->spellLevel
) + 6.0f
) / (float)(getLevel());
4775 if(LvlFactor
> 1.0f
)
4778 // Spellmod SpellDamage
4779 float SpellModSpellDamage
= 100.0f
;
4780 if (GetTypeId() == TYPEID_PLAYER
)
4781 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_SPELL_DAMAGE
,SpellModSpellDamage
);
4782 SpellModSpellDamage
/= 100.0f
;
4784 float DoneActualBenefit
= DoneAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
* SpellModSpellDamage
/ 100.0f
;
4785 float TakenActualBenefit
= TakenAdvertisedBenefit
* (CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
/ 100.0f
;
4787 float tmpDamage
= (float(pdamage
)+DoneActualBenefit
)*DoneTotalMod
;
4788 tmpDamage
= (tmpDamage
+TakenActualBenefit
)*TakenTotalMod
;
4790 return tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
4793 bool Unit::SpellCriticalBonus(SpellEntry
const *spellProto
, int32
*peffect
, Unit
*pVictim
)
4795 // Chance to crit is computed from INT and LEVEL as follows:
4796 // chance = base + INT / (rate0 + rate1 * LEVEL)
4797 // The formula keeps the crit chance at %5 on every level unless the player
4798 // increases his intelligence by other means (enchants, buffs, talents, ...)
4799 if(spellProto
->Id
== 15290 || spellProto
->Id
== 39373) return false;
4801 float crit_chance
= 0.0f
;
4804 if (GetTypeId() != TYPEID_PLAYER
)
4807 // TODO: can creatures have critical chance auras?
4808 crit_chance
= m_baseSpellCritChance
;
4809 AuraList
const& mSpellCritSchool
= GetAurasByType(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
);
4810 for(AuraList::const_iterator i
= mSpellCritSchool
.begin(); i
!= mSpellCritSchool
.end(); ++i
)
4811 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
4812 crit_chance
+= (*i
)->GetModifier()->m_amount
;
4815 crit_chance
= GetFloatValue( PLAYER_SPELL_CRIT_PERCENTAGE1
+ spellProto
->School
);
4818 // only players use intelligence for critical chance computations
4819 if (GetTypeId() == TYPEID_PLAYER
)
4821 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRITICAL_CHANCE
, crit_chance
);
4828 AuraList
const& mAttackerSpellCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
);
4829 for(AuraList::const_iterator i
= mAttackerSpellCrit
.begin(); i
!= mAttackerSpellCrit
.end(); ++i
)
4830 if((*i
)->GetModifier()->m_miscvalue
== -2 || ((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
4831 crit_chance
+= (*i
)->GetModifier()->m_amount
;
4833 // flat: Resilience - reduce crit chance by x%
4834 crit_chance
-= pVictim
->m_modResilience
;
4836 // flat: scripted (increase crit chance ... against ... target by x%
4837 AuraList
const& mOverrideClassScript
= GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
);
4838 for(AuraList::const_iterator i
= mOverrideClassScript
.begin(); i
!= mOverrideClassScript
.end(); ++i
)
4840 switch((*i
)->GetModifier()->m_miscvalue
)
4843 case 849: if(pVictim
->isFrozen()) crit_chance
+= 10; break;
4845 case 910: if(pVictim
->isFrozen()) crit_chance
+= 20; break;
4847 case 911: if(pVictim
->isFrozen()) crit_chance
+= 30; break;
4849 case 912: if(pVictim
->isFrozen()) crit_chance
+= 40; break;
4851 case 913: if(pVictim
->isFrozen()) crit_chance
+= 50; break;
4856 AuraList
const& mAttackerSWCrit
= pVictim
->GetAurasByType(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
);
4857 for(AuraList::const_iterator i
= mAttackerSWCrit
.begin(); i
!= mAttackerSWCrit
.end(); ++i
)
4858 crit_chance
+= (*i
)->GetModifier()->m_amount
;
4861 crit_chance
= crit_chance
> 0.0 ? crit_chance
: 0.0;
4862 if (roll_chance_f(crit_chance
))
4864 int32 crit_bonus
= *peffect
/ 2;
4865 if (GetTypeId() == TYPEID_PLAYER
) // adds additional damage to crit_bonus (from talents)
4866 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_CRIT_DAMAGE_BONUS
, crit_bonus
);
4868 *peffect
+= crit_bonus
;
4869 // Resilience - reduce crit damage by 2x%
4871 *peffect
-= int32(pVictim
->m_modResilience
* 2/100 * (*peffect
));
4878 uint32
Unit::SpellHealingBonus(SpellEntry
const *spellProto
, uint32 healamount
, DamageEffectType damagetype
, Unit
*pVictim
)
4882 // Vampiric Embrace, Shadowmend - cannot critically heal
4883 if(spellProto
->Id
== 15290 || spellProto
->Id
== 39373) return healamount
;
4885 int32 AdvertisedBenefit
= 0;
4886 uint32 CastingTime
= GetCastTime(sCastTimesStore
.LookupEntry(spellProto
->CastingTimeIndex
));
4887 if (CastingTime
> 7000) CastingTime
= 7000;
4888 if (CastingTime
< 1500) CastingTime
= 1500;
4889 if (spellProto
->Effect
[0] == SPELL_EFFECT_APPLY_AURA
) CastingTime
= 3500;
4891 AuraList
const& mHealingDone
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE
);
4892 for(AuraList::const_iterator i
= mHealingDone
.begin();i
!= mHealingDone
.end(); ++i
)
4893 if(((*i
)->GetModifier()->m_miscvalue
& (int32
)(1<<spellProto
->School
)) != 0)
4894 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4896 // Healing bonus of spirit, intellect and strength
4897 if (GetTypeId() == TYPEID_PLAYER
)
4899 AdvertisedBenefit
+= int32(GetStat(STAT_SPIRIT
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_SPIRIT
) / 100.0f
);
4900 AdvertisedBenefit
+= int32(GetStat(STAT_INTELLECT
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT
) / 100.0f
);
4901 AdvertisedBenefit
+= int32(GetStat(STAT_STRENGTH
) * GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HEALING_OF_STRENGTH
) / 100.0f
);
4905 AdvertisedBenefit
+= pVictim
->GetTotalAuraModifier(SPELL_AURA_MOD_HEALING
);
4908 if (spellProto
->SpellFamilyName
== SPELLFAMILY_PALADIN
&& (spellProto
->SpellFamilyFlags
& 0xC0000000))
4910 AuraList
const& mDummyAuras
= pVictim
->GetAurasByType(SPELL_AURA_DUMMY
);
4911 for(AuraList::const_iterator i
= mDummyAuras
.begin();i
!= mDummyAuras
.end(); ++i
)
4912 if((*i
)->GetSpellProto()->SpellVisual
== 9180)
4914 if ((spellProto
->SpellFamilyFlags
& 0x40000000) && (*i
)->GetEffIndex() == 1)
4915 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4917 else if ((spellProto
->SpellFamilyFlags
& 0x80000000) && (*i
)->GetEffIndex() == 0)
4918 AdvertisedBenefit
+= (*i
)->GetModifier()->m_amount
;
4921 // Healing over Time spells
4922 float DotFactor
= 1.0f
;
4923 if(damagetype
== DOT
)
4926 uint32 DotDuration
= GetDuration(spellProto
);
4928 if(DotDuration
> 30000) DotDuration
= 30000;
4929 DotFactor
= DotDuration
/ 15000.0f
;
4931 for(int j
= 0; j
< 3; j
++)
4932 if(spellProto
->Effect
[j
] == 6) x
= j
;
4934 if(spellProto
->EffectAmplitude
[x
] != 0)
4935 DotTicks
= DotDuration
/ spellProto
->EffectAmplitude
[x
];
4937 AdvertisedBenefit
/= DotTicks
;
4941 float LvlPenalty
= 0.0f
;
4942 if(spellProto
->spellLevel
< 20)
4943 LvlPenalty
= (20.0f
- (float)(spellProto
->spellLevel
)) * 3.75f
;
4944 float LvlFactor
= ((float)(spellProto
->spellLevel
) + 6.0f
) / (float)(getLevel());
4945 if(LvlFactor
> 1.0f
)
4948 float ActualBenefit
= (float)AdvertisedBenefit
* ((float)CastingTime
/ 3500.0f
) * (100.0f
- LvlPenalty
) * LvlFactor
* DotFactor
/ 100.0f
;
4950 // use float as more appropriate for negative values and percent applying
4951 float heal
= healamount
+ ActualBenefit
;
4953 // TODO: check for ALL/SPELLS type
4954 // Healing done percent
4955 AuraList
const& mHealingDonePct
= GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT
);
4956 for(AuraList::const_iterator i
= mHealingDonePct
.begin();i
!= mHealingDonePct
.end(); ++i
)
4957 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
4959 // Healing taken percent
4960 AuraList
const& mHealingPct
= pVictim
->GetAurasByType(SPELL_AURA_MOD_HEALING_PCT
);
4961 for(AuraList::const_iterator i
= mHealingPct
.begin();i
!= mHealingPct
.end(); ++i
)
4962 heal
*= (100.0f
+ (*i
)->GetModifier()->m_amount
) / 100.0f
;
4964 if (heal
< 0) heal
= 0;
4966 return uint32(heal
);
4969 bool Unit::IsImmunedToPhysicalDamage() const
4971 //If m_immuneToDamage type contain magic, IMMUNE damage.
4972 SpellImmuneList
const& damageImmList
= m_spellImmune
[IMMUNITY_DAMAGE
];
4973 for (SpellImmuneList::const_iterator itr
= damageImmList
.begin(); itr
!= damageImmList
.end(); ++itr
)
4974 if(itr
->type
& IMMUNE_DAMAGE_PHYSICAL
)
4977 //If m_immuneToSchool type contain this school type, IMMUNE damage.
4978 SpellImmuneList
const& spellImmList
= m_spellImmune
[IMMUNITY_SCHOOL
];
4979 for (SpellImmuneList::const_iterator itr
= spellImmList
.begin(); itr
!= spellImmList
.end(); ++itr
)
4980 if(itr
->type
& IMMUNE_SCHOOL_PHYSICAL
)
4986 bool Unit::IsImmunedToSpellDamage(SpellEntry
const* spellInfo
) const
4988 //If m_immuneToDamage type contain magic, IMMUNE damage.
4989 SpellImmuneList
const& damageList
= m_spellImmune
[IMMUNITY_DAMAGE
];
4990 for (SpellImmuneList::const_iterator itr
= damageList
.begin(); itr
!= damageList
.end(); ++itr
)
4991 if(itr
->type
& uint32(1<<spellInfo
->School
))
4994 //If m_immuneToSchool type contain this school type, IMMUNE damage.
4995 SpellImmuneList
const& schoolList
= m_spellImmune
[IMMUNITY_SCHOOL
];
4996 for (SpellImmuneList::const_iterator itr
= schoolList
.begin(); itr
!= schoolList
.end(); ++itr
)
4997 if(itr
->type
& uint32(1<<spellInfo
->School
))
5003 bool Unit::IsImmunedToSpell(SpellEntry
const* spellInfo
) const
5008 SpellImmuneList
const& dispelList
= m_spellImmune
[IMMUNITY_DISPEL
];
5009 for(SpellImmuneList::const_iterator itr
= dispelList
.begin(); itr
!= dispelList
.end(); ++itr
)
5010 if(itr
->type
== spellInfo
->Dispel
)
5013 SpellImmuneList
const& mechanicList
= m_spellImmune
[IMMUNITY_MECHANIC
];
5014 for(SpellImmuneList::const_iterator itr
= mechanicList
.begin(); itr
!= mechanicList
.end(); ++itr
)
5015 if(itr
->type
== spellInfo
->Mechanic
)
5019 AuraList
const& mModMechanicRes
= GetAurasByType(SPELL_AURA_MOD_MECHANIC_RESISTANCE
);
5020 for(AuraList::const_iterator i
= mModMechanicRes
.begin();i
!= mModMechanicRes
.end(); ++i
)
5021 if((*i
)->GetModifier()->m_miscvalue
== int32(spellInfo
->Mechanic
))
5022 chance
+= (*i
)->GetModifier()->m_amount
;
5023 if(roll_chance_i(chance
))
5029 bool Unit::IsImmunedToSpellEffect(uint32 effect
) const
5031 //If m_immuneToEffect type contain this effect type, IMMUNE effect.
5032 SpellImmuneList
const& effectList
= m_spellImmune
[IMMUNITY_EFFECT
];
5033 for (SpellImmuneList::const_iterator itr
= effectList
.begin(); itr
!= effectList
.end(); ++itr
)
5034 if(itr
->type
== effect
)
5040 bool Unit::IsDamageToThreatSpell(SpellEntry
const * spellInfo
) const
5045 uint32 family
= spellInfo
->SpellFamilyName
;
5046 uint32 flags
= spellInfo
->SpellFamilyFlags
;
5048 if((family
== 5 && flags
== 256) || //Searing Pain
5049 (family
== 6 && flags
== 8192) || //Mind Blast
5050 (family
== 11 && flags
== 1048576)) //Earth Shock
5056 void Unit::MeleeDamageBonus(Unit
*pVictim
, uint32
*pdamage
,WeaponAttackType attType
)
5058 if(!pVictim
) return;
5063 uint32 creatureTypeMask
= GetCreatureTypeMask();
5065 if(GetTypeId() != TYPEID_PLAYER
&& ((Creature
*)this)->isPet())
5067 if(getPowerType() == POWER_FOCUS
)
5069 uint32 happiness
= GetPower(POWER_HAPPINESS
);
5070 if(happiness
>=666000)
5071 *pdamage
= uint32(*pdamage
* 1.25);
5072 else if(happiness
<333000)
5073 *pdamage
= uint32(*pdamage
* 0.75);
5074 else *pdamage
= uint32(*pdamage
* 1.0);
5078 // Taken/Done fixed damage bonus auras
5079 int32 DoneFlatBenefit
= 0;
5080 int32 TakenFlatBenefit
= 0;
5082 // ..done (for creature type by mask) in taken
5083 AuraList
const& mDamageDoneCreature
= this->GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
);
5084 for(AuraList::const_iterator i
= mDamageDoneCreature
.begin();i
!= mDamageDoneCreature
.end(); ++i
)
5085 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
5086 DoneFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5089 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
5091 // ..done (base at attack power and creature type)
5092 AuraList
const& mCreatureAttackPower
= GetAurasByType(SPELL_AURA_MOD_CREATURE_ATTACK_POWER
);
5093 for(AuraList::const_iterator i
= mCreatureAttackPower
.begin();i
!= mCreatureAttackPower
.end(); ++i
)
5094 if(creatureTypeMask
& uint32((*i
)->GetModifier()->m_miscvalue
))
5095 DoneFlatBenefit
+= int32((*i
)->GetModifier()->m_amount
/14.0f
* GetAttackTime(attType
)/1000);
5097 // ..done (base at attack power for marked target)
5098 if(attType
== RANGED_ATTACK
)
5100 AuraList
const& mRangedAttackPowerAttackerBonus
= pVictim
->GetAurasByType(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
);
5101 for(AuraList::const_iterator i
= mRangedAttackPowerAttackerBonus
.begin();i
!= mRangedAttackPowerAttackerBonus
.end(); ++i
)
5102 DoneFlatBenefit
+= int32((*i
)->GetModifier()->m_amount
/14.0f
* GetAttackTime(RANGED_ATTACK
)/1000);
5106 AuraList
const& mDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN
);
5107 for(AuraList::const_iterator i
= mDamageTaken
.begin();i
!= mDamageTaken
.end(); ++i
)
5108 if((*i
)->GetModifier()->m_miscvalue
& IMMUNE_SCHOOL_PHYSICAL
)
5109 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5111 if(attType
!=RANGED_ATTACK
)
5113 AuraList
const& mModMeleeDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
);
5114 for(AuraList::const_iterator i
= mModMeleeDamageTaken
.begin(); i
!= mModMeleeDamageTaken
.end(); ++i
)
5115 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5119 AuraList
const& mModRangedDamageTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
);
5120 for(AuraList::const_iterator i
= mModRangedDamageTaken
.begin(); i
!= mModRangedDamageTaken
.end(); ++i
)
5121 TakenFlatBenefit
+= (*i
)->GetModifier()->m_amount
;
5124 // Done/Taken total percent damage auras
5125 float TakenTotalMod
= 1;
5128 // SPELL_AURA_MOD_DAMAGE_PERCENT_DONE included in weapon damage
5129 // SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT included in weapon damage
5132 AuraList
const& mModDamagePercentTaken
= pVictim
->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
);
5133 for(AuraList::const_iterator i
= mModDamagePercentTaken
.begin(); i
!= mModDamagePercentTaken
.end(); ++i
)
5134 if((*i
)->GetModifier()->m_miscvalue
& IMMUNE_SCHOOL_PHYSICAL
)
5135 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5137 if(attType
!= RANGED_ATTACK
)
5139 AuraList
const& mModMeleeDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
);
5140 for(AuraList::const_iterator i
= mModMeleeDamageTakenPercent
.begin(); i
!= mModMeleeDamageTakenPercent
.end(); ++i
)
5141 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5145 AuraList
const& mModRangedDamageTakenPercent
= pVictim
->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
);
5146 for(AuraList::const_iterator i
= mModRangedDamageTakenPercent
.begin(); i
!= mModRangedDamageTakenPercent
.end(); ++i
)
5147 TakenTotalMod
*= ((*i
)->GetModifier()->m_amount
+100.0f
)/100.0f
;
5150 float tmpDamage
= ((int32(*pdamage
) + DoneFlatBenefit
) + TakenFlatBenefit
)*TakenTotalMod
;
5152 // bonus result can be negative
5153 *pdamage
= tmpDamage
> 0 ? uint32(tmpDamage
) : 0;
5156 void Unit::ApplySpellImmune(uint32 spellId
, uint32 op
, uint32 type
, bool apply
)
5160 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(), next
; itr
!= m_spellImmune
[op
].end(); itr
= next
)
5163 if(itr
->type
== type
)
5165 m_spellImmune
[op
].erase(itr
);
5166 next
= m_spellImmune
[op
].begin();
5170 Immune
.spellId
= spellId
;
5172 m_spellImmune
[op
].push_back(Immune
);
5176 for (SpellImmuneList::iterator itr
= m_spellImmune
[op
].begin(); itr
!= m_spellImmune
[op
].end(); ++itr
)
5178 if(itr
->spellId
== spellId
)
5180 m_spellImmune
[op
].erase(itr
);
5188 float Unit::GetWeaponProcChance() const
5190 // normalized proc chance for weapon attack speed
5191 // (odd formulae...)
5192 if(isAttackReady(BASE_ATTACK
))
5193 return (GetAttackTime(BASE_ATTACK
) * 1.8f
/ 1000.0f
);
5194 else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK
))
5195 return (GetAttackTime(OFF_ATTACK
) * 1.6f
/ 1000.0f
);
5199 float Unit::GetPPMProcChance(uint32 WeaponSpeed
, float PPM
) const
5201 // proc per minute chance calculation
5202 if (PPM
<= 0) return 0.0f
;
5203 uint32 result
= uint32((WeaponSpeed
* PPM
) / 600.0f
); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
5207 void Unit::Mount(uint32 mount
, bool taxi
)
5212 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, mount
);
5214 uint32 flag
= UNIT_FLAG_MOUNT
;
5216 flag
|= UNIT_FLAG_DISABLE_MOVE
;
5218 SetFlag( UNIT_FIELD_FLAGS
, flag
);
5221 if(GetTypeId() == TYPEID_PLAYER
)
5223 Pet
* pet
= GetPet();
5226 if(pet
->getPetType() == SUMMON_PET
|| pet
->getPetType() == HUNTER_PET
)
5228 ((Player
*)this)->SetOldPetNumber(pet
->GetCharmInfo()->GetPetNumber());
5229 ((Player
*)this)->SetOldPetSpell(pet
->GetUInt32Value(UNIT_CREATED_BY_SPELL
));
5232 ((Player
*)this)->RemovePet(NULL
,PET_SAVE_NOT_IN_SLOT
);
5235 ((Player
*)this)->SetOldPetNumber(0);
5239 void Unit::Unmount()
5244 SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID
, 0);
5245 RemoveFlag( UNIT_FIELD_FLAGS
,UNIT_FLAG_DISABLE_MOVE
| UNIT_FLAG_MOUNT
);
5247 if(GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->GetOldPetNumber() && isAlive())
5249 Pet
* NewPet
= new Pet(this);
5250 if(!NewPet
->LoadPetFromDB(this, 0, ((Player
*)this)->GetOldPetNumber(), true))
5253 ((Player
*)this)->SetOldPetNumber(0);
5257 void Unit::SetInCombat()
5259 m_CombatTimer
= 5000;
5260 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
5262 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
5263 SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
5266 void Unit::ClearInCombat(bool force
)
5268 // wait aura and combat timer expire
5269 if(!force
&& HasAuraType(SPELL_AURA_INTERRUPT_REGEN
))
5273 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_IN_COMBAT
);
5275 if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER
&& ((Creature
*)this)->isPet()))
5276 RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_PET_IN_COMBAT
);
5278 // remove combo points
5279 if(GetTypeId()==TYPEID_PLAYER
)
5280 ((Player
*)this)->ClearComboPoints();
5283 bool Unit::isTargetableForAttack()
5285 if (GetTypeId()==TYPEID_PLAYER
&& ((Player
*)this)->isGameMaster())
5287 return isAlive() && !hasUnitState(UNIT_STAT_DIED
)&& !isInFlight() /*&& !isStealth()*/;
5290 int32
Unit::ModifyHealth(int32 dVal
)
5297 int32 curHealth
= (int32
)GetHealth();
5299 int32 val
= dVal
+ curHealth
;
5306 int32 maxHealth
= (int32
)GetMaxHealth();
5311 gain
= val
- curHealth
;
5313 else if(curHealth
!= maxHealth
)
5315 SetHealth(maxHealth
);
5316 gain
= maxHealth
- curHealth
;
5322 int32
Unit::ModifyPower(Powers power
, int32 dVal
)
5329 int32 curPower
= (int32
)GetPower(power
);
5331 int32 val
= dVal
+ curPower
;
5338 int32 maxPower
= (int32
)GetMaxPower(power
);
5342 SetPower(power
,val
);
5343 gain
= val
- curPower
;
5345 else if(curPower
!= maxPower
)
5347 SetPower(power
,maxPower
);
5348 gain
= maxPower
- curPower
;
5354 bool Unit::isVisibleForOrDetect(Unit
const* u
, bool detect
, bool inVisibleList
) const
5359 // Always can see self
5363 // player visible for other player if not logout and at same transport
5364 // including case when player is out of world
5365 bool at_same_transport
=
5366 GetTypeId() == TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
&&
5367 !((Player
*)this)->GetSession()->PlayerLogout() && !((Player
*)u
)->GetSession()->PlayerLogout() &&
5368 !((Player
*)this)->GetSession()->PlayerLoading() && !((Player
*)u
)->GetSession()->PlayerLoading() &&
5369 ((Player
*)this)->GetTransport() && ((Player
*)this)->GetTransport() == ((Player
*)u
)->GetTransport();
5372 if(!at_same_transport
&& (!IsInWorld() || !u
->IsInWorld()))
5375 // always seen by owner
5376 if(GetCharmerOrOwnerGUID()==u
->GetGUID())
5379 // Grid dead/alive checks
5380 if( u
->GetTypeId()==TYPEID_PLAYER
)
5382 // non visible at grid for any stealth state
5383 if(!IsVisibleInGridForPlayer((Player
*)u
))
5386 // if player is dead then he can't detect anyone in anycases
5392 // all dead creatures/players not visible for any creatures
5393 if(!u
->isAlive() || !isAlive())
5397 // different visible distance checks
5398 if(u
->isInFlight()) // what see player in flight
5400 // use object grey distance for all (only see objects any way)
5401 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceInFlight()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
5404 else if(!isAlive()) // distance for show body
5406 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForObject()+(inVisibleList
? World::GetVisibleObjectGreyDistance() : 0.0f
)))
5409 else if(GetTypeId()==TYPEID_PLAYER
) // distance for show player
5411 if(u
->GetTypeId()==TYPEID_PLAYER
)
5413 // Players far than max visible distance for player or not in our map are not visible too
5414 if (!at_same_transport
&& !IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5419 // Units far than max visible distance for creature or not in our map are not visible too
5420 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5424 else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed
5426 // Pet/charmed far than max visible distance for player or not in our map are not visible too
5427 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5430 else // distance for show creature
5432 // Units far than max visible distance for creature or not in our map are not visible too
5433 if (!IsWithinDistInMap(u
,World::GetMaxVisibleDistanceForCreature()+(inVisibleList
? World::GetVisibleUnitGreyDistance() : 0.0f
)))
5437 // Visible units, always are visible for all units, except for units under invisibility
5438 if (m_Visibility
== VISIBILITY_ON
&& u
->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY
)
5441 // GMs are visible for higher gms (or players are visible for gms)
5442 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->isGameMaster())
5443 return (GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->GetSession()->GetSecurity() <= ((Player
*)u
)->GetSession()->GetSecurity());
5445 // non faction visibility non-breakable for non-GMs
5446 if (m_Visibility
== VISIBILITY_OFF
)
5449 // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility
5450 if (m_Visibility
== VISIBILITY_GROUP_INVISIBILITY
)
5452 if(u
->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY
|| m_invisibilityvalue
<= u
->m_detectInvisibility
)
5456 // Units that can detect invisibility always are visible for units that can be detected
5457 if (u
->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY
)
5459 if(m_detectInvisibility
>= u
->m_invisibilityvalue
)
5463 // Stealth/invisible not hostile units, not visible (except Player-with-Player case)
5464 if (!u
->IsHostileTo(this))
5466 // 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)
5467 if(GetTypeId()==TYPEID_PLAYER
&& u
->GetTypeId()==TYPEID_PLAYER
)
5469 if(((Player
*)this)->IsGroupVisibleFor(((Player
*)u
)))
5472 // else apply same rules as for hostile case (detecting check)
5477 // Hunter mark functionality
5478 AuraList
const& auras
= GetAurasByType(SPELL_AURA_MOD_STALKED
);
5479 for(AuraList::const_iterator iter
= auras
.begin(); iter
!= auras
.end(); ++iter
)
5480 if((*iter
)->GetCasterGUID()==u
->GetGUID())
5484 // unit got in stealth in this moment and must ignore old detected state
5485 // invisibility not have chance for detection
5486 if (m_Visibility
== VISIBILITY_ON
|| m_Visibility
== VISIBILITY_GROUP_NO_DETECT
|| m_Visibility
== VISIBILITY_GROUP_INVISIBILITY
)
5489 // NOW ONLY STEALTH CASE
5491 // stealth and detected
5492 if (u
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)u
)->HaveAtClient(this) )
5495 //if in non-detect mode then invisible for unit
5500 bool IsVisible
= true;
5501 bool isInFront
= u
->isInFront(this,World::GetMaxVisibleDistanceForObject());
5502 float distance
= sqrt(GetDistanceSq(u
));
5504 // If is attacked then stealth is lost, some creature can use stealth too
5505 if (this->isAttacked())
5508 // If there is collision rogue is seen regardless of level difference
5509 // TODO: check sizes in DB
5510 if (distance
< 0.24f
)
5513 //If a mob or player is stunned he will not be able to detect stealth
5514 if ((u
->hasUnitState(UNIT_STAT_STUNDED
)) && (u
!= this))
5520 // Cases based on level difference and position
5521 int32 levelDiff
= u
->getLevel() - this->getLevel();
5523 //If mob is 5 levels more than player he gets detected automaticly
5524 if (u
->GetTypeId()!=TYPEID_PLAYER
&& levelDiff
> 5)
5527 // If victim has more than 5 lvls above caster
5528 if ((this->GetTypeId() == TYPEID_UNIT
)&& ( levelDiff
> 5 ))
5531 // If caster has more than 5 levels above victim
5532 if ((this->GetTypeId() == TYPEID_UNIT
)&& ( levelDiff
< -5 ))
5538 float modifier
= 1; // 100 pct
5539 float pvpMultiplier
= 0;
5540 float distanceFormula
= 0;
5542 //This allows to check talent tree and will add addition stealth dependant on used points)
5543 uint32 stealthMod
= GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL
);
5544 //****************************************************************************************
5545 // Stealth detection calculation
5546 int32 x
= (((u
->m_detectStealth
+1) / 5) - (((m_stealthvalue
+1) / 5) + (stealthMod
/5) + 59));
5549 // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp
5550 if (u
->GetTypeId() != TYPEID_PLAYER
)
5551 rank
= ((Creature
const*)u
)->GetCreatureInfo()->rank
;
5553 // Probabilty of being seen
5555 distanceFormula
= ((sWorld
.getRate(RATE_CREATURE_AGGRO
) * 16) / (abs(levelDiff
) + 1.5)) * 2;
5557 distanceFormula
= (((sWorld
.getRate(RATE_CREATURE_AGGRO
) * 16)) / 2) * (levelDiff
+ 1);
5559 // Original probability values
5560 // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference
5561 //at this distance, the detector has to be a 15% prob of detect
5562 float averageDist
= 1 - 0.11016949 * x
+ 0.00301637 * x
* x
;
5563 if (averageDist
< 1) averageDist
= 1;
5566 if (distance
> averageDist
)
5567 //prob between 10% and 0%
5568 prob
= (averageDist
- 200 + 9 * distance
) / (averageDist
- 20);
5570 prob
= 75 - (60 / averageDist
) * distance
; //prob between 15% and 75% (75% max prob)
5572 // If is not in front, probability floor
5578 // Mob rank affects modifier
5579 modifier
= rank
<= 4 ? 1 + rank
* 0.2f
: 1;
5581 if (distance
< 0.24f
)
5586 // PVP distance assigned depending on level
5587 if (this->GetTypeId() == TYPEID_UNIT
)
5589 // Level diff floor/ceiling <-5,5>
5590 pvpMultiplier
= levelDiff
> 5 ? 12 : levelDiff
< 5 ? 2 : 7 + levelDiff
;
5591 pvpMultiplier
= pvpMultiplier
- (x
/ 100);
5594 // PVP stealth handler
5595 if (this->GetTypeId() == TYPEID_PLAYER
)
5597 // Do not loose stealth when coming from back
5604 // If comes in front
5605 if (isInFront
&& (distance
>= pvpMultiplier
))
5611 if (isInFront
&& (distance
< pvpMultiplier
))
5618 // PVE stealth handler
5619 // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled
5620 // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you
5621 if ((distance
< 100) && (distance
> ((distanceFormula
* 2) * modifier
)) && (distance
> 0.24f
))
5627 //If victim is level lower or more probability of detection drops
5628 if ((levelDiff
< 0) && (distance
> 0.24f
))
5630 if (abs(levelDiff
) > 4)
5634 if (rand_chance() > ( prob
* modifier
/ (30 + levelDiff
* 5)))
5639 // Level detection based on level, the higher the mob level the higher the chance of detection.
5640 if ((distance
> 0.24f
) && (levelDiff
< 5) && (levelDiff
>= 0))
5642 if (rand_chance() > ((prob
* modifier
) / (30 - levelDiff
* 5) ))
5651 // Didn't match any criteria ?
5652 DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance
,levelDiff
,u
->GetTypeId(),prob
, modifier
);
5658 void Unit::SetVisibility(UnitVisibility x
)
5664 Map
*m
= MapManager::Instance().GetMap(GetMapId(), this);
5666 if(GetTypeId()==TYPEID_PLAYER
)
5667 m
->PlayerRelocation((Player
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5669 m
->CreatureRelocation((Creature
*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
5673 float Unit::GetSpeed( UnitMoveType mtype
) const
5675 return m_speed_rate
[mtype
]*baseMoveSpeed
[mtype
];
5678 void Unit::SetSpeed(UnitMoveType mtype
, float rate
, bool forced
)
5680 m_speed_rate
[mtype
] = 1.0f
;
5681 ApplySpeedMod(mtype
, rate
, forced
, true);
5684 void Unit::ApplySpeedMod(UnitMoveType mtype
, float rate
, bool forced
, bool apply
)
5689 m_speed_rate
[mtype
] *= rate
;
5691 m_speed_rate
[mtype
] /= rate
;
5696 if(forced
) { data
.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE
, 16); }
5697 else { data
.Initialize(MSG_MOVE_SET_WALK_SPEED
, 16); }
5700 if(forced
) { data
.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE
, 16); }
5701 else { data
.Initialize(MSG_MOVE_SET_RUN_SPEED
, 16); }
5704 if(forced
) { data
.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE
, 16); }
5705 else { data
.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED
, 16); }
5708 if(forced
) { data
.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE
, 16); }
5709 else { data
.Initialize(MSG_MOVE_SET_SWIM_SPEED
, 16); }
5712 if(forced
) { data
.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE
, 16); }
5713 else { data
.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED
, 16); }
5716 if(forced
) { data
.Initialize(SMSG_FORCE_TURN_RATE_CHANGE
, 16); }
5717 else { data
.Initialize(MSG_MOVE_SET_TURN_RATE
, 16); }
5720 if(forced
) { data
.Initialize(SMSG_FORCE_FLY_SPEED_CHANGE
, 16); }
5721 else { data
.Initialize(SMSG_MOVE_SET_FLY_SPEED
, 16); }
5726 sLog
.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype
);
5730 data
.append(GetPackGUID());
5732 if (mtype
== MOVE_RUN
) data
<< uint8(0); // new 2.1.0
5733 data
<< float(GetSpeed(mtype
));
5734 SendMessageToSet( &data
, true );
5736 if(Pet
* pet
= GetPet())
5737 pet
->SetSpeed(mtype
,m_speed_rate
[mtype
],forced
);
5740 void Unit::SetHover(bool on
)
5743 CastSpell(this,11010,true);
5745 RemoveAurasDueToSpell(11010);
5748 void Unit::setDeathState(DeathState s
)
5754 if(IsNonMeleeSpellCasted(false))
5755 InterruptNonMeleeSpells(false);
5760 RemoveAllAurasOnDeath();
5761 UnsummonAllTotems();
5763 if (m_deathState
!= ALIVE
&& s
== ALIVE
)
5765 //_ApplyAllAuraMods();
5770 /*########################################
5772 ######## AGGRO SYSTEM ########
5774 ########################################*/
5775 bool Unit::CanHaveThreatList() const
5777 if(GetTypeId() == TYPEID_UNIT
&& !((Creature
*)this)->isPet() && !((Creature
*)this)->isTotem() )
5783 //======================================================================
5785 float Unit::ApplyTotalThreatModifier(float threat
, SpellSchools school
)
5787 if(!HasAuraType(SPELL_AURA_MOD_THREAT
))
5790 if(school
>= MAX_SPELL_SCHOOL
)
5792 sLog
.outError("Unit::ApplyTotalThreatModifier: Spell school with out-of-range value: %u",uint32(school
));
5796 return threat
* m_threatModifier
[school
];
5799 //======================================================================
5801 void Unit::AddThreat(Unit
* pVictim
, float threat
, SpellSchools school
, SpellEntry
const *threatSpell
)
5803 // Only mobs can manage threat lists
5804 if(CanHaveThreatList())
5805 m_ThreatManager
.addThreat(pVictim
, threat
, school
, threatSpell
);
5808 //======================================================================
5810 void Unit::DeleteThreatList()
5812 m_ThreatManager
.clearReferences();
5815 //======================================================================
5817 void Unit::TauntApply(Unit
* taunter
)
5819 assert(GetTypeId()== TYPEID_UNIT
);
5821 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
5824 if(!CanHaveThreatList())
5827 Unit
*target
= getVictim();
5828 if(target
&& target
== taunter
)
5831 SetInFront(taunter
);
5832 if (((Creature
*)this)->AI())
5833 ((Creature
*)this)->AI()->AttackStart(taunter
);
5835 m_ThreatManager
.tauntApply(taunter
);
5838 //======================================================================
5840 void Unit::TauntFadeOut(Unit
*taunter
)
5842 assert(GetTypeId()== TYPEID_UNIT
);
5844 if(!taunter
|| (taunter
->GetTypeId() == TYPEID_PLAYER
&& ((Player
*)taunter
)->isGameMaster()))
5847 if(!CanHaveThreatList())
5850 Unit
*target
= getVictim();
5851 if(!target
|| target
!= taunter
)
5854 if(m_ThreatManager
.isThreatListEmpty())
5856 if(((Creature
*)this)->AI())
5857 ((Creature
*)this)->AI()->EnterEvadeMode();
5861 m_ThreatManager
.tauntFadeOut(taunter
);
5862 target
= m_ThreatManager
.getHostilTarget();
5864 if (target
&& target
!= taunter
)
5867 if (((Creature
*)this)->AI())
5868 ((Creature
*)this)->AI()->AttackStart(target
);
5872 //======================================================================
5874 bool Unit::SelectHostilTarget()
5876 //function provides main threat functionality
5877 //next-victim-selection algorithm and evade mode are called
5878 //threat list sorting etc.
5880 assert(GetTypeId()== TYPEID_UNIT
);
5881 Unit
* target
= NULL
;
5883 //This function only useful once AI has been initilazied
5884 if (!((Creature
*)this)->AI())
5887 if(!m_ThreatManager
.isThreatListEmpty())
5889 if(!HasAuraType(SPELL_AURA_MOD_TAUNT
))
5891 target
= m_ThreatManager
.getHostilTarget();
5898 ((Creature
*)this)->AI()->AttackStart(target
);
5902 if(isInCombat() && !HasAuraType(SPELL_AURA_MOD_TAUNT
) && CanFreeMove() && m_attackers
.empty())
5903 ((Creature
*)this)->AI()->EnterEvadeMode();
5908 //======================================================================
5909 //======================================================================
5910 //======================================================================
5912 void Unit::CalculateSpellDamageAndDuration(int32
* damage
, int32
* duration
, SpellEntry
const* spellProto
, uint8 effect_index
, int32 effBasePoints
)
5914 Player
* unitPlayer
= (GetTypeId() == TYPEID_PLAYER
) ? (Player
*)this : NULL
;
5916 uint8 comboPoints
= unitPlayer
? unitPlayer
->GetComboPoints() : 0;
5917 bool needClearCombo
= false;
5924 level
= getLevel() - spellProto
->spellLevel
;
5925 if (level
> spellProto
->maxLevel
&& spellProto
->maxLevel
> 0)
5926 level
= spellProto
->maxLevel
;
5928 float basePointsPerLevel
= spellProto
->EffectRealPointsPerLevel
[effect_index
];
5929 float randomPointsPerLevel
= spellProto
->EffectDicePerLevel
[effect_index
];
5930 int32 basePoints
= int32(effBasePoints
+ level
* basePointsPerLevel
);
5931 int32 randomPoints
= int32(spellProto
->EffectDieSides
[effect_index
] + level
* randomPointsPerLevel
);
5932 float comboDamage
= spellProto
->EffectPointsPerComboPoint
[effect_index
];
5934 value
= basePoints
+ rand32(spellProto
->EffectBaseDice
[effect_index
], randomPoints
);
5936 if(int32(spellProto
->EffectBaseDice
[effect_index
]) != randomPoints
&& GetTypeId() == TYPEID_UNIT
&& ((Creature
*)this)->isPet())
5937 value
+= ((Pet
*)this)->GetBonusDamage(); //bonus damage only on spells without fixed basePoints?)
5939 if(comboDamage
!= 0 && unitPlayer
&& m_attacking
&& (m_attacking
->GetGUID() == unitPlayer
->GetComboTarget()))
5941 value
+= (int32
)(comboDamage
* comboPoints
);
5944 if( spellProto
->SpellIconID
== 514 && spellProto
->SpellFamilyName
== SPELLFAMILY_ROGUE
)
5945 value
+= (int32
)(GetTotalAttackPowerValue(BASE_ATTACK
) * comboPoints
* 0.03);
5947 needClearCombo
= true;
5950 if (GetTypeId() == TYPEID_PLAYER
)
5952 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_ALL_EFFECTS
, value
);
5953 switch(effect_index
)
5956 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT1
, value
);
5959 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT2
, value
);
5962 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_EFFECT3
, value
);
5966 ((Player
*)this)->ApplySpellMod(spellProto
->Id
, SPELLMOD_DAMAGE
, value
);
5975 int32 minduration
= GetDuration(spellProto
);
5976 int32 maxduration
= GetMaxDuration(spellProto
);
5978 if( minduration
!= -1 && minduration
!= maxduration
)
5980 *duration
= minduration
+ int32((maxduration
- minduration
) * comboPoints
/ 5);
5981 needClearCombo
= true;
5984 *duration
= minduration
;
5987 if(unitPlayer
&& needClearCombo
)
5988 unitPlayer
->SetComboPoints(unitPlayer
->GetComboTarget(), 0);
5991 void Unit::AddDiminishing(DiminishingMechanics mech
, uint32 hitTime
, uint32 hitCount
)
5993 m_Diminishing
.push_back(DiminishingReturn(mech
,hitTime
,hitCount
));
5996 DiminishingLevels
Unit::GetDiminishing(DiminishingMechanics mech
)
5998 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6000 if(i
->Mechanic
!= mech
) continue;
6001 if(!i
->hitCount
) return DIMINISHING_LEVEL_1
;
6002 if(!i
->hitTime
) return DIMINISHING_LEVEL_1
;
6003 // If last spell was casted more than 15 seconds ago - reset the count.
6004 if((getMSTime() - i
->hitTime
) > 15000)
6006 i
->hitCount
= DIMINISHING_LEVEL_1
;
6007 return DIMINISHING_LEVEL_1
;
6009 // or else increase the count.
6012 if(i
->hitCount
> DIMINISHING_LEVEL_2
)
6014 i
->hitCount
= DIMINISHING_LEVEL_IMMUNE
;
6015 return DIMINISHING_LEVEL_IMMUNE
;
6017 else return DiminishingLevels(i
->hitCount
);
6020 return DIMINISHING_LEVEL_1
;
6023 void Unit::IncrDiminishing(DiminishingMechanics mech
, uint32 duration
)
6025 // Checking for existing in the table
6026 bool IsExist
= false;
6027 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6029 if(i
->Mechanic
!= mech
)
6033 if(i
->hitCount
< DIMINISHING_LEVEL_IMMUNE
)
6038 case DIMINISHING_LEVEL_2
: i
->hitTime
= uint32(getMSTime() + duration
); break;
6039 case DIMINISHING_LEVEL_3
: i
->hitTime
= uint32(getMSTime() + duration
*0.5); break;
6040 case DIMINISHING_LEVEL_IMMUNE
: i
->hitTime
= uint32(getMSTime() + duration
*0.25); break;
6048 AddDiminishing(mech
,uint32(getMSTime() + duration
),DIMINISHING_LEVEL_2
);
6051 void Unit::UpdateDiminishingTime(DiminishingMechanics mech
)
6053 // Checking for existing in the table
6054 bool IsExist
= false;
6055 for(Diminishing::iterator i
= m_Diminishing
.begin(); i
!= m_Diminishing
.end(); ++i
)
6057 if(i
->Mechanic
!= mech
)
6061 i
->hitTime
= getMSTime();
6066 AddDiminishing(mech
,getMSTime(),DIMINISHING_LEVEL_1
);
6069 DiminishingMechanics
Unit::Mechanic2DiminishingMechanics(uint32 mech
)
6073 case MECHANIC_CHARM
: case MECHANIC_FEAR
: case MECHANIC_SLEEP
:
6074 return DIMINISHING_MECHANIC_CHARM
;
6075 case MECHANIC_CONFUSED
: case MECHANIC_KNOCKOUT
: case MECHANIC_POLYMORPH
:
6076 return DIMINISHING_MECHANIC_CONFUSE
;
6077 case MECHANIC_ROOT
: case MECHANIC_FREEZE
:
6078 return DIMINISHING_MECHANIC_ROOT
;
6079 case MECHANIC_STUNDED
:
6080 return DIMINISHING_MECHANIC_STUN
;
6081 case MECHANIC_CHASE
:
6082 return DIMINISHING_MECHANIC_SPEED
;
6086 return DIMINISHING_NONE
;
6089 float Unit::ApplyDiminishingToDuration(DiminishingMechanics mech
, int32 duration
,Unit
* caster
)
6091 if(duration
== -1 || mech
== DIMINISHING_NONE
)
6094 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
6095 if(duration
> 10000)
6097 // test pet/charm masters instead pets/charmeds
6098 Unit
const* targetOwner
= GetCharmerOrOwner();
6099 Unit
const* casterOwner
= caster
->GetCharmerOrOwner();
6101 Unit
const* target
= targetOwner
? targetOwner
: this;
6102 Unit
const* source
= casterOwner
? casterOwner
: caster
;
6104 if(target
->GetTypeId() == TYPEID_PLAYER
&& source
->GetTypeId() == TYPEID_PLAYER
)
6110 // Stun diminishing is applies to mobs too
6111 if(mech
== DIMINISHING_MECHANIC_STUN
|| GetTypeId() == TYPEID_PLAYER
)
6113 DiminishingLevels diminish
= GetDiminishing(mech
);
6116 case DIMINISHING_LEVEL_1
: IncrDiminishing(mech
, duration
); break;
6117 case DIMINISHING_LEVEL_2
: IncrDiminishing(mech
, duration
); mod
= 0.5f
; break;
6118 case DIMINISHING_LEVEL_3
: IncrDiminishing(mech
, duration
); mod
= 0.25f
; break;
6119 case DIMINISHING_LEVEL_IMMUNE
: mod
= 0.0f
; break;
6127 Creature
* Unit::SummonCreature(uint32 id
, float x
, float y
, float z
, float ang
,TempSummonType spwtype
,uint32 despwtime
)
6129 TemporarySummon
* pCreature
= new TemporarySummon(this,this);
6131 pCreature
->SetInstanceId(GetInstanceId());
6133 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), GetMapId(), x
, y
, z
, ang
, id
))
6139 pCreature
->Summon(spwtype
, despwtime
);
6141 //return the creature therewith the summoner has access to it
6145 Unit
* Unit::GetUnit(WorldObject
& object
, uint64 guid
)
6147 return ObjectAccessor::Instance().GetUnit(object
,guid
);
6150 bool Unit::isVisibleForInState( Player
const* u
, bool inVisibleList
) const
6152 return isVisibleForOrDetect(u
,false,inVisibleList
);
6155 uint32
Unit::GetCreatureType() const
6157 if(GetTypeId() == TYPEID_PLAYER
)
6159 switch(((Player
const*)this)->m_form
)
6166 case FORM_GHOSTWOLF
:
6167 case FORM_SWIFT_FLIGHT
:
6169 return CREATURE_TYPE_BEAST
;
6171 case FORM_SPIRITOFREDEMPTION
:
6172 return CREATURE_TYPE_ELEMENTAL
;
6175 return CREATURE_TYPE_HUMANOID
;
6179 return ((Creature
*)this)->GetCreatureInfo()->type
;
6182 /*#######################################
6184 ######## STAT SYSTEM ########
6186 #######################################*/
6188 bool Unit::HandleStatModifier(UnitMods unitMod
, UnitModifierType modifierType
, float amount
, bool apply
)
6190 if(unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
6192 sLog
.outError("ERROR in HandleStatModifier(): nonexisted UnitMods or wrong UnitModifierType!");
6198 switch(modifierType
)
6202 m_auraModifiersGroup
[unitMod
][modifierType
] += apply
? amount
: -amount
;
6206 if(amount
<= -100.0f
) //small hack-fix for -100% modifiers
6209 val
= (100.0f
+ amount
) / 100.0f
;
6210 m_auraModifiersGroup
[unitMod
][modifierType
] *= apply
? val
: (1.0f
/val
);
6217 if(!CanModifyStats())
6222 case UNIT_MOD_STAT_STRENGTH
:
6223 case UNIT_MOD_STAT_AGILITY
:
6224 case UNIT_MOD_STAT_STAMINA
:
6225 case UNIT_MOD_STAT_INTELLECT
:
6226 case UNIT_MOD_STAT_SPIRIT
: UpdateStats(GetStatByAuraGroup(unitMod
)); break;
6228 case UNIT_MOD_ARMOR
: UpdateArmor(); break;
6229 case UNIT_MOD_HEALTH
: UpdateMaxHealth(); break;
6233 case UNIT_MOD_FOCUS
:
6234 case UNIT_MOD_ENERGY
:
6235 case UNIT_MOD_HAPPINESS
: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod
)); break;
6237 case UNIT_MOD_RESISTANCE_HOLY
:
6238 case UNIT_MOD_RESISTANCE_FIRE
:
6239 case UNIT_MOD_RESISTANCE_NATURE
:
6240 case UNIT_MOD_RESISTANCE_FROST
:
6241 case UNIT_MOD_RESISTANCE_SHADOW
:
6242 case UNIT_MOD_RESISTANCE_ARCANE
: UpdateResistances(GetSpellSchoolByAuraGroup(unitMod
)); break;
6244 case UNIT_MOD_ATTACK_POWER
: UpdateAttackPowerAndDamage(); break;
6245 case UNIT_MOD_ATTACK_POWER_RANGED
: UpdateAttackPowerAndDamage(true); break;
6247 case UNIT_MOD_DAMAGE_MAINHAND
: UpdateDamagePhysical(BASE_ATTACK
); break;
6248 case UNIT_MOD_DAMAGE_OFFHAND
: UpdateDamagePhysical(OFF_ATTACK
); break;
6249 case UNIT_MOD_DAMAGE_RANGED
: UpdateDamagePhysical(RANGED_ATTACK
); break;
6258 float Unit::GetModifierValue(UnitMods unitMod
, UnitModifierType modifierType
) const
6260 if( unitMod
>= UNIT_MOD_END
|| modifierType
>= MODIFIER_TYPE_END
)
6262 sLog
.outError("ERROR: trial to access nonexisted modifier value from UnitMods!");
6266 if(modifierType
== TOTAL_PCT
&& m_auraModifiersGroup
[unitMod
][modifierType
] <= 0.0f
)
6269 return m_auraModifiersGroup
[unitMod
][modifierType
];
6272 float Unit::GetTotalStatValue(Stats stat
) const
6274 UnitMods unitMod
= UnitMods(UNIT_MOD_STAT_START
+ stat
);
6276 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
6279 // value = ((base_value * base_pct) + total_value) * total_pct
6280 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
] + GetCreateStat(stat
);
6281 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
6282 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
6283 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
6288 float Unit::GetTotalAuraModValue(UnitMods unitMod
) const
6290 if(unitMod
>= UNIT_MOD_END
)
6292 sLog
.outError("ERROR: trial to access nonexisted UnitMods in GetTotalAuraModValue()!");
6296 if(m_auraModifiersGroup
[unitMod
][TOTAL_PCT
] <= 0.0f
)
6299 float value
= m_auraModifiersGroup
[unitMod
][BASE_VALUE
];
6300 value
*= m_auraModifiersGroup
[unitMod
][BASE_PCT
];
6301 value
+= m_auraModifiersGroup
[unitMod
][TOTAL_VALUE
];
6302 value
*= m_auraModifiersGroup
[unitMod
][TOTAL_PCT
];
6307 SpellSchools
Unit::GetSpellSchoolByAuraGroup(UnitMods unitMod
) const
6309 SpellSchools school
= SPELL_SCHOOL_NORMAL
;
6313 case UNIT_MOD_RESISTANCE_HOLY
: school
= SPELL_SCHOOL_HOLY
; break;
6314 case UNIT_MOD_RESISTANCE_FIRE
: school
= SPELL_SCHOOL_FIRE
; break;
6315 case UNIT_MOD_RESISTANCE_NATURE
: school
= SPELL_SCHOOL_NATURE
; break;
6316 case UNIT_MOD_RESISTANCE_FROST
: school
= SPELL_SCHOOL_FROST
; break;
6317 case UNIT_MOD_RESISTANCE_SHADOW
: school
= SPELL_SCHOOL_SHADOW
; break;
6318 case UNIT_MOD_RESISTANCE_ARCANE
: school
= SPELL_SCHOOL_ARCANE
; break;
6327 Stats
Unit::GetStatByAuraGroup(UnitMods unitMod
) const
6329 Stats stat
= STAT_STRENGTH
;
6333 case UNIT_MOD_STAT_STRENGTH
: stat
= STAT_STRENGTH
; break;
6334 case UNIT_MOD_STAT_AGILITY
: stat
= STAT_AGILITY
; break;
6335 case UNIT_MOD_STAT_STAMINA
: stat
= STAT_STAMINA
; break;
6336 case UNIT_MOD_STAT_INTELLECT
: stat
= STAT_INTELLECT
; break;
6337 case UNIT_MOD_STAT_SPIRIT
: stat
= STAT_SPIRIT
; break;
6346 Powers
Unit::GetPowerTypeByAuraGroup(UnitMods unitMod
) const
6348 Powers power
= POWER_MANA
;
6352 case UNIT_MOD_MANA
: power
= POWER_MANA
; break;
6353 case UNIT_MOD_RAGE
: power
= POWER_RAGE
; break;
6354 case UNIT_MOD_FOCUS
: power
= POWER_FOCUS
; break;
6355 case UNIT_MOD_ENERGY
: power
= POWER_ENERGY
; break;
6356 case UNIT_MOD_HAPPINESS
: power
= POWER_HAPPINESS
; break;
6365 float Unit::GetTotalAttackPowerValue(WeaponAttackType attType
) const
6367 UnitMods unitMod
= (attType
== RANGED_ATTACK
) ? UNIT_MOD_ATTACK_POWER_RANGED
: UNIT_MOD_ATTACK_POWER
;
6369 float val
= GetTotalAuraModValue(unitMod
);
6376 float Unit::GetWeaponDamageRange(WeaponAttackType attType
,WeaponDamageRange type
) const
6378 if (attType
== OFF_ATTACK
&& !haveOffhandWeapon())
6381 return m_weaponDamage
[attType
][type
];
6384 void Unit::SetLevel(uint32 lvl
)
6386 SetUInt32Value(UNIT_FIELD_LEVEL
,lvl
);
6389 if (GetTypeId() == TYPEID_PLAYER
)
6390 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL
);
6393 void Unit::SetHealth(uint32 val
)
6395 uint32 maxHealth
= GetMaxHealth();
6399 SetUInt32Value(UNIT_FIELD_HEALTH
,val
);
6402 if (GetTypeId() == TYPEID_PLAYER
)
6403 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP
);
6406 void Unit::SetMaxHealth(uint32 val
)
6408 uint32 health
= GetHealth();
6409 SetUInt32Value(UNIT_FIELD_MAXHEALTH
,val
);
6412 if (GetTypeId() == TYPEID_PLAYER
)
6413 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_HP
);
6419 void Unit::SetPower(Powers power
, uint32 val
)
6421 uint32 maxPower
= GetMaxPower(power
);
6425 SetStatInt32Value(UNIT_FIELD_POWER1
+ power
,val
);
6428 if (GetTypeId() == TYPEID_PLAYER
)
6429 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
6432 void Unit::SetMaxPower(Powers power
, uint32 val
)
6434 uint32 cur_power
= GetPower(power
);
6435 SetStatInt32Value(UNIT_FIELD_MAXPOWER1
+ power
,val
);
6438 if (GetTypeId() == TYPEID_PLAYER
)
6439 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
6442 SetPower(power
, val
);
6445 void Unit::ApplyPowerMod(Powers power
, uint32 val
, bool apply
)
6447 ApplyModUInt32Value(UNIT_FIELD_POWER1
+power
, val
, apply
);
6450 if (GetTypeId() == TYPEID_PLAYER
)
6451 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER
);
6454 void Unit::ApplyMaxPowerMod(Powers power
, uint32 val
, bool apply
)
6456 ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1
+power
, val
, apply
);
6459 if (GetTypeId() == TYPEID_PLAYER
)
6460 ((Player
*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER
);
6463 void Unit::ApplyAuraProcTriggerDamage( Aura
* aura
, bool apply
)
6465 AuraList
& tAuraProcTriggerDamage
= m_modAuras
[SPELL_AURA_PROC_TRIGGER_DAMAGE
];
6467 tAuraProcTriggerDamage
.push_back(aura
);
6469 tAuraProcTriggerDamage
.remove(aura
);
6472 uint32
Unit::GetCreatePowers( Powers power
) const
6474 // POWER_FOCUS and POWER_HAPPINESS only have hunter pet
6477 case POWER_MANA
: return GetCreateMana();
6478 case POWER_RAGE
: return 1000;
6479 case POWER_FOCUS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 100);
6480 case POWER_ENERGY
: return 100;
6481 case POWER_HAPPINESS
: return (GetTypeId()==TYPEID_PLAYER
|| !((Creature
const*)this)->isPet() || ((Pet
const*)this)->getPetType()!=HUNTER_PET
? 0 : 1050000);
6487 void Unit::CleanupsBeforeDelete()
6489 if(m_uint32Values
) // only for fully created object
6491 m_Events
.KillAllEvents();
6494 getHostilRefManager().setOnlineOfflineState(false);
6500 CharmInfo
* Unit::InitCharmInfo(Unit
*charm
)
6503 m_charmInfo
= new CharmInfo(charm
);
6507 CharmInfo::CharmInfo(Unit
* unit
)
6508 : m_unit(unit
), m_CommandState(COMMAND_STAY
), m_ReactSate(REACT_PASSIVE
), m_petnumber(0)
6510 for(int i
=0; i
<4; ++i
)
6512 m_charmspells
[i
].spellId
= 0;
6513 m_charmspells
[i
].active
= ACT_DISABLED
;
6517 void CharmInfo::InitPetActionBar()
6519 // the first 3 SpellOrActions are attack, follow and stay
6520 for(uint32 i
= 0; i
< 3; i
++)
6522 PetActionBar
[i
].Type
= ACT_COMMAND
;
6523 PetActionBar
[i
].SpellOrAction
= COMMAND_ATTACK
- i
;
6525 PetActionBar
[i
+ 7].Type
= ACT_REACTION
;
6526 PetActionBar
[i
+ 7].SpellOrAction
= COMMAND_ATTACK
- i
;
6528 for(uint32 i
=0; i
< 4; i
++)
6530 PetActionBar
[i
+ 3].Type
= ACT_DISABLED
;
6531 PetActionBar
[i
+ 3].SpellOrAction
= 0;
6535 void CharmInfo::InitEmptyActionBar()
6537 for(uint32 x
= 1; x
< 10; ++x
)
6539 PetActionBar
[x
].Type
= ACT_CAST
;
6540 PetActionBar
[x
].SpellOrAction
= 0;
6542 PetActionBar
[0].Type
= ACT_COMMAND
;
6543 PetActionBar
[0].SpellOrAction
= COMMAND_ATTACK
;
6546 void CharmInfo::InitPossessCreateSpells()
6548 if(m_unit
->GetTypeId() == TYPEID_PLAYER
)
6551 InitEmptyActionBar(); //charm action bar
6553 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6555 if (IsPassiveSpell(((Creature
*)m_unit
)->m_spells
[x
]))
6556 m_unit
->CastSpell(m_unit
, ((Creature
*)m_unit
)->m_spells
[x
], true);
6558 AddSpellToAB(0, ((Creature
*)m_unit
)->m_spells
[x
], ACT_CAST
);
6562 void CharmInfo::InitCharmCreateSpells()
6564 if(m_unit
->GetTypeId() == TYPEID_PLAYER
) //charmed players don't have spells
6566 InitEmptyActionBar();
6572 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6574 uint32 spellId
= ((Creature
*)m_unit
)->m_spells
[x
];
6575 m_charmspells
[x
].spellId
= spellId
;
6580 if (IsPassiveSpell(spellId
))
6582 m_unit
->CastSpell(m_unit
, spellId
, true);
6583 m_charmspells
[x
].active
= ACT_PASSIVE
;
6587 ActiveStates newstate
;
6588 bool onlyselfcast
= true;
6589 SpellEntry
const *spellInfo
= sSpellStore
.LookupEntry(spellId
);
6591 if(!spellInfo
) onlyselfcast
= false;
6592 for(uint32 i
= 0;i
<3 && onlyselfcast
;++i
) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
6594 if(spellInfo
->EffectImplicitTargetA
[i
] != TARGET_SELF
&& spellInfo
->EffectImplicitTargetA
[i
] != 0)
6595 onlyselfcast
= false;
6598 if(onlyselfcast
|| !IsPositiveSpell(spellId
)) //only self cast and spells versus enemies are autocastable
6599 newstate
= ACT_DISABLED
;
6601 newstate
= ACT_CAST
;
6603 AddSpellToAB(0, spellId
, newstate
);
6608 bool CharmInfo::AddSpellToAB(uint32 oldid
, uint32 newid
, ActiveStates newstate
)
6610 for(uint8 i
= 0; i
< 10; i
++)
6612 if((PetActionBar
[i
].Type
== ACT_DISABLED
|| PetActionBar
[i
].Type
== ACT_ENABLED
|| PetActionBar
[i
].Type
== ACT_CAST
) && PetActionBar
[i
].SpellOrAction
== oldid
)
6614 PetActionBar
[i
].SpellOrAction
= newid
;
6617 if(newstate
== ACT_DECIDE
)
6618 PetActionBar
[i
].Type
= ACT_DISABLED
;
6620 PetActionBar
[i
].Type
= newstate
;
6629 void CharmInfo::ToggleCreatureAutocast(uint32 spellid
, bool apply
)
6631 if(IsPassiveSpell(spellid
))
6634 for(uint32 x
= 0; x
< CREATURE_MAX_SPELLS
; ++x
)
6636 if(spellid
== m_charmspells
[x
].spellId
)
6638 m_charmspells
[x
].active
= apply
? ACT_ENABLED
: ACT_DISABLED
;
6643 void CharmInfo::SetPetNumber(uint32 petnumber
, bool statwindow
)
6645 m_petnumber
= petnumber
;
6647 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, m_petnumber
);
6649 m_unit
->SetUInt32Value(UNIT_FIELD_PETNUMBER
, 0);
6652 bool Unit::isFrozen() const
6654 AuraList
const& mRoot
= GetAurasByType(SPELL_AURA_MOD_ROOT
);
6655 for(AuraList::const_iterator i
= mRoot
.begin(); i
!= mRoot
.end(); ++i
)
6656 if( (*i
)->GetSpellProto()->School
== SPELL_SCHOOL_FROST
)
6661 struct ProcTriggeredData
6663 ProcTriggeredData(SpellEntry
const * _spellInfo
, uint32 _spellParam
, Aura
* _triggeredByAura
)
6664 : spellInfo(_spellInfo
), spellParam(_spellParam
), triggeredByAura(_triggeredByAura
),
6665 triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura
->GetId(),triggeredByAura
->GetEffIndex()))
6668 SpellEntry
const * spellInfo
;
6670 Aura
* triggeredByAura
;
6671 Unit::spellEffectPair triggeredByAura_SpellPair
;
6674 typedef std::list
< ProcTriggeredData
> ProcTriggeredList
;
6676 void Unit::ProcDamageAndSpellFor( bool isVictim
, Unit
* pTarget
, uint32 procFlag
, AuraTypeSet
const& procAuraTypes
, WeaponAttackType attType
, SpellEntry
const * procSpell
, uint32 damage
)
6678 for(AuraTypeSet::const_iterator aur
= procAuraTypes
.begin(); aur
!= procAuraTypes
.end(); ++aur
)
6680 // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE)
6681 ProcTriggeredList procTriggered
;
6683 AuraList
const& auras
= GetAurasByType(*aur
);
6684 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
6688 SpellEntry
const *spellProto
= (*i
)->GetSpellProto();
6692 SpellProcEventEntry
const *spellProcEvent
= objmgr
.GetSpellProcEvent(spellProto
->Id
);
6695 // used to prevent spam in log about same non-handled spells
6696 static Unit::AuraTypeSet nonHandledSpellProcSet
;
6698 if(spellProto
->procFlags
!= 0 && nonHandledSpellProcSet
.find(spellProto
->Id
)==nonHandledSpellProcSet
.end())
6700 sLog
.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto
->Id
,(isVictim
?"a victim's":"an attacker's"));
6701 nonHandledSpellProcSet
.insert(spellProto
->Id
);
6704 // spell.dbc use totally different flags, that only can create problems if used.
6708 // Check spellProcEvent data requirements
6709 if(!ObjectMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent
, procSpell
,procFlag
))
6712 // Check if current equipment allows aura to proc
6713 if(!isVictim
&& GetTypeId() == TYPEID_PLAYER
&& ((Player
*)this)->IsUseEquipedWeapon())
6715 if(spellProto
->EquippedItemClass
== ITEM_CLASS_WEAPON
)
6718 if(attType
== BASE_ATTACK
)
6719 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_MAINHAND
);
6720 else if (attType
== OFF_ATTACK
)
6721 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
6723 item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_RANGED
);
6725 if(!item
|| item
->IsBroken() || item
->GetProto()->Class
!= ITEM_CLASS_WEAPON
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
6728 else if(spellProto
->EquippedItemClass
== ITEM_CLASS_ARMOR
)
6730 // Check if player is wearing shield
6731 Item
*item
= ((Player
*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0
, EQUIPMENT_SLOT_OFFHAND
);
6732 if(!item
|| item
->IsBroken() || item
->GetProto()->Class
!= ITEM_CLASS_ARMOR
|| !((1<<item
->GetProto()->SubClass
) & spellProto
->EquippedItemSubClassMask
))
6737 // Need to use floats here, cuz calculated PPM chance often is about 1-2%
6738 float chance
= (float)spellProto
->procChance
;
6739 if(GetTypeId() == TYPEID_PLAYER
)
6740 ((Player
*)this)->ApplySpellMod(spellProto
->Id
,SPELLMOD_CHANCE_OF_SUCCESS
,chance
);
6742 if(!isVictim
&& spellProcEvent
->ppmRate
!= 0)
6744 uint32 WeaponSpeed
= GetAttackTime(attType
);
6745 chance
= GetPPMProcChance(WeaponSpeed
, spellProcEvent
->ppmRate
);
6748 if(roll_chance_f(chance
))
6750 if((*i
)->m_procCharges
> 0)
6751 (*i
)->m_procCharges
-= 1;
6753 uint32 i_spell_eff
= (*i
)->GetEffIndex();
6755 int32 i_spell_param
;
6758 case SPELL_AURA_PROC_TRIGGER_SPELL
: i_spell_param
= procFlag
; break;
6759 case SPELL_AURA_DUMMY
: i_spell_param
= i_spell_eff
; break;
6760 default: i_spell_param
= (*i
)->GetModifier()->m_amount
; break;
6763 procTriggered
.push_back( ProcTriggeredData(spellProto
,i_spell_param
,*i
) );
6767 // Handle effects proceed this time
6768 for(ProcTriggeredList::iterator i
= procTriggered
.begin(); i
!= procTriggered
.end(); ++i
)
6770 // Some auras can be deleted in function called in this loop (except first, ofc)
6771 // Until storing auars in std::multimap to hard check deleting by another way
6772 if(i
!= procTriggered
.begin())
6775 AuraMap::const_iterator lower
= GetAuras().lower_bound(i
->triggeredByAura_SpellPair
);
6776 AuraMap::const_iterator upper
= GetAuras().upper_bound(i
->triggeredByAura_SpellPair
);
6777 for(AuraMap::const_iterator itr
= lower
; itr
!= upper
; ++itr
)
6779 if(itr
->second
==i
->triggeredByAura
)
6788 sLog
.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur
,i
->triggeredByAura_SpellPair
.first
,i
->triggeredByAura_SpellPair
.second
);
6789 sLog
.outError("It can be deleted one from early proccesed auras:");
6790 for(ProcTriggeredList::iterator i2
= procTriggered
.begin(); i
!= i2
; ++i2
)
6791 sLog
.outError(" Spell aura %u (id:%u effect:%u)",*aur
,i2
->triggeredByAura_SpellPair
.first
,i2
->triggeredByAura_SpellPair
.second
);
6792 sLog
.outError(" <end of list>");
6797 if(*aur
== SPELL_AURA_PROC_TRIGGER_SPELL
)
6799 sLog
.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
6800 HandleProcTriggerSpell(pTarget
, damage
, i
->triggeredByAura
, procSpell
,i
->spellParam
);
6802 else if(*aur
== SPELL_AURA_PROC_TRIGGER_DAMAGE
)
6804 sLog
.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", i
->spellParam
, i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
6805 uint32 damage
= i
->spellParam
;
6806 // TODO: remove hack for Seal of Righteousness. That should not be there
6807 if(!isVictim
&& i
->spellInfo
->SpellVisual
== 7986)
6808 damage
= (damage
* GetAttackTime(BASE_ATTACK
))/60/1000;
6809 SpellNonMeleeDamageLog(pTarget
, i
->spellInfo
->Id
, damage
, true, true);
6811 else if(*aur
== SPELL_AURA_DUMMY
)
6813 sLog
.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", i
->spellInfo
->Id
,(isVictim
?"a victim's":"an attacker's"),i
->triggeredByAura
->GetId());
6814 HandleDummyAuraProc(pTarget
, i
->spellInfo
, i
->spellParam
, damage
, i
->triggeredByAura
, procSpell
, procFlag
);
6818 // Safely remove auras with zero charges
6819 for(AuraList::const_iterator i
= auras
.begin(), next
; i
!= auras
.end(); i
= next
)
6822 if((*i
)->m_procCharges
== 0)
6824 RemoveAurasDueToSpell((*i
)->GetId());
6825 next
= auras
.begin();