TrinityCore
Loading...
Searching...
No Matches
Unit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Unit.h"
19#include "AbstractFollower.h"
20#include "Battlefield.h"
21#include "BattlefieldMgr.h"
22#include "Battleground.h"
23#include "BattlegroundPackets.h"
24#include "BattlegroundScore.h"
25#include "CellImpl.h"
26#include "CharacterCache.h"
27#include "Chat.h"
28#include "ChatPackets.h"
29#include "ChatTextBuilder.h"
30#include "CombatPackets.h"
31#include "Common.h"
32#include "ConditionMgr.h"
33#include "Containers.h"
34#include "CreatureAI.h"
35#include "CreatureAIImpl.h"
36#include "CreatureGroups.h"
37#include "Formulas.h"
38#include "GameClient.h"
39#include "GameObjectAI.h"
40#include "GameTime.h"
41#include "GridNotifiersImpl.h"
42#include "Group.h"
43#include "InstanceSaveMgr.h"
44#include "InstanceScript.h"
45#include "Item.h"
46#include "Log.h"
47#include "LootMgr.h"
48#include "MotionMaster.h"
49#include "MovementGenerator.h"
50#include "MovementPackets.h"
51#include "MoveSpline.h"
52#include "MoveSplineInit.h"
53#include "ObjectAccessor.h"
54#include "ObjectMgr.h"
55#include "Opcodes.h"
56#include "OutdoorPvP.h"
58#include "PassiveAI.h"
59#include "PetAI.h"
60#include "Pet.h"
61#include "PetPackets.h"
62#include "Player.h"
63#include "PlayerAI.h"
64#include "QuestDef.h"
65#include "ReputationMgr.h"
66#include "ScheduledChangeAI.h"
67#include "SpellAuraEffects.h"
68#include "SpellAuras.h"
69#include "Spell.h"
70#include "SpellInfo.h"
71#include "SpellHistory.h"
72#include "SpellMgr.h"
73#include "SpellPackets.h"
74#include "StringConvert.h"
75#include "TemporarySummon.h"
76#include "Transport.h"
77#include "Totem.h"
78#include "UnitAI.h"
79#include "UpdateFieldFlags.h"
80#include "Util.h"
81#include "Vehicle.h"
82#include "World.h"
83#include "WorldPacket.h"
84#include "WorldSession.h"
85#include <cmath>
86
88{
89 2.5f, // MOVE_WALK
90 7.0f, // MOVE_RUN
91 4.5f, // MOVE_RUN_BACK
92 4.722222f, // MOVE_SWIM
93 2.5f, // MOVE_SWIM_BACK
94 3.141594f, // MOVE_TURN_RATE
95 7.0f, // MOVE_FLIGHT
96 4.5f, // MOVE_FLIGHT_BACK
97 3.14f // MOVE_PITCH_RATE
98};
99
101{
102 2.5f, // MOVE_WALK
103 7.0f, // MOVE_RUN
104 4.5f, // MOVE_RUN_BACK
105 4.722222f, // MOVE_SWIM
106 2.5f, // MOVE_SWIM_BACK
107 3.141594f, // MOVE_TURN_RATE
108 7.0f, // MOVE_FLIGHT
109 4.5f, // MOVE_FLIGHT_BACK
110 3.14f // MOVE_PITCH_RATE
111};
112
113DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
114 : m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
115 m_absorb(0), m_resist(0), m_block(0), m_hitMask(0)
116{
117}
118
120 : m_attacker(dmg1.m_attacker), m_victim(dmg1.m_victim), m_damage(dmg1.m_damage + dmg2.m_damage), m_spellInfo(dmg1.m_spellInfo), m_schoolMask(SpellSchoolMask(dmg1.m_schoolMask | dmg2.m_schoolMask)),
121 m_damageType(dmg1.m_damageType), m_attackType(dmg1.m_attackType), m_absorb(dmg1.m_absorb + dmg2.m_absorb), m_resist(dmg1.m_resist + dmg2.m_resist), m_block(dmg1.m_block), m_hitMask(dmg1.m_hitMask | dmg2.m_hitMask)
122{
123}
124
125DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) : DamageInfo(DamageInfo(dmgInfo, 0), DamageInfo(dmgInfo, 1))
126{
127}
128
129DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex)
130 : m_attacker(dmgInfo.Attacker), m_victim(dmgInfo.Target), m_damage(dmgInfo.Damages[damageIndex].Damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.Damages[damageIndex].DamageSchoolMask)),
131 m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.AttackType), m_absorb(dmgInfo.Damages[damageIndex].Absorb), m_resist(dmgInfo.Damages[damageIndex].Resist), m_block(dmgInfo.Blocked), m_hitMask(0)
132{
133 switch (dmgInfo.TargetState)
134 {
137 break;
140 break;
141 }
142
145
146 if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
148
149 if (m_block)
151
152 bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
154 switch (dmgInfo.HitOutCome)
155 {
156 case MELEE_HIT_MISS:
158 break;
159 case MELEE_HIT_DODGE:
161 break;
162 case MELEE_HIT_PARRY:
164 break;
165 case MELEE_HIT_EVADE:
167 break;
168 case MELEE_HIT_BLOCK:
171 case MELEE_HIT_NORMAL:
172 if (!damageNullified)
174 break;
175 case MELEE_HIT_CRIT:
176 if (!damageNullified)
178 break;
179 }
180}
181
182DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask)
183 : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage),
184 m_spellInfo(sSpellMgr->GetSpellInfo(spellNonMeleeDamage.SpellID)), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
185 m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
186{
187 if (spellNonMeleeDamage.blocked)
189 if (spellNonMeleeDamage.absorb)
191}
192
194{
195 amount = std::max(amount, -static_cast<int32>(GetDamage()));
196 m_damage += amount;
197}
198
200{
201 amount = std::min(amount, GetDamage());
202 m_absorb += amount;
203 m_damage -= amount;
205}
206
208{
209 amount = std::min(amount, GetDamage());
210 m_resist += amount;
211 m_damage -= amount;
212 if (!m_damage)
213 {
216 }
217}
218
220{
221 amount = std::min(amount, GetDamage());
222 m_block += amount;
223 m_damage -= amount;
225 if (!m_damage)
226 {
229 }
230}
231
233{
234 return m_hitMask;
235}
236
237HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
238 : _healer(healer), _target(target), _heal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
239{
240}
241
243{
244 amount = std::min(amount, GetHeal());
245 _absorb += amount;
246 _heal -= amount;
247 amount = std::min(amount, GetEffectiveHeal());
248 _effectiveHeal -= amount;
250}
251
253{
254 return _hitMask;
255}
256
258 uint32 typeMask, uint32 spellTypeMask,
259 uint32 spellPhaseMask, uint32 hitMask,
260 Spell* spell, DamageInfo* damageInfo,
261 HealInfo* healInfo) :
262 _actor(actor), _actionTarget(actionTarget),
263 _typeMask(typeMask), _spellTypeMask(spellTypeMask),
264 _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell),
265 _damageInfo(damageInfo), _healInfo(healInfo)
266{ }
267
269{
270 if (_spell)
271 return _spell->GetSpellInfo();
272 if (_damageInfo)
273 return _damageInfo->GetSpellInfo();
274 if (_healInfo)
275 return _healInfo->GetSpellInfo();
276 return nullptr;
277}
278
280{
281 if (_spell)
282 return _spell->GetSpellInfo()->GetSchoolMask();
283 if (_damageInfo)
284 return _damageInfo->GetSchoolMask();
285 if (_healInfo)
286 return _healInfo->GetSchoolMask();
288}
289
290DispelableAura::DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
291 _aura(aura), _chance(dispelChance), _charges(dispelCharges)
292{
293}
294
296
298{
299 return roll_chance_i(_chance);
300}
301
302Unit::Unit(bool isWorldObject) :
303 WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(new Movement::MoveSpline()),
304 m_ControlledByPlayer(false), m_AutoRepeatFirstCast(false), m_procDeep(0), m_transformSpell(0),
305 m_removedAurasCount(0), m_charmer(nullptr), m_charmed(nullptr),
306 i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), m_vehicleKit(nullptr),
307 m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), m_threatManager(this),
308 m_aiLocked(false), m_comboTarget(nullptr), m_comboPoints(0), _spellHistory(new SpellHistory(this))
309{
312
314
321
322 m_canDualWield = false;
323
325
326 m_state = 0;
328
329 for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
330 m_currentSpells[i] = nullptr;
331
332 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
333 m_SummonSlot[i].Clear();
334
335 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
336 m_ObjectSlot[i].Clear();
337
339
340 m_interruptMask = 0;
341 m_canModifyStats = false;
342
343 for (uint8 i = 0; i < UNIT_MOD_END; ++i)
344 {
349 }
350 // implement 50% base damage from offhand
352
353 for (uint8 i = 0; i < MAX_ATTACK; ++i)
354 {
357
358 m_weaponDamage[i][MINDAMAGE][1] = 0.f;
359 m_weaponDamage[i][MAXDAMAGE][1] = 0.f;
360 }
361
362 for (uint8 i = 0; i < MAX_STATS; ++i)
363 m_createStats[i] = 0.0f;
364
365 m_attacking = nullptr;
366 m_modMeleeHitChance = 0.0f;
368 m_modSpellHitChance = 0.0f;
370
371 m_lastManaUse = 0;
372
373 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
374 m_speed_rate[i] = 1.0f;
375
376 m_charmInfo = nullptr;
377 _gameClientMovingMe = nullptr;
378
379 // remove aurastates allowing special moves
380 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
381 m_reactiveTimer[i] = 0;
382
383 m_cleanupDone = false;
385
387
388 _lastLiquid = nullptr;
389
390 _oldFactionId = 0;
391 _isWalkingBeforeCharm = false;
392 _instantCast = false;
393 _isCombatDisallowed = false;
394
396}
397
399// Methods of class Unit
401{
402 // set current spells as deletable
403 for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
404 if (m_currentSpells[i])
405 {
407 m_currentSpells[i] = nullptr;
408 }
409
411
413
414 delete std::exchange(i_motionMaster, nullptr);
415 delete std::exchange(m_charmInfo, nullptr);
416 delete std::exchange(movespline, nullptr);
417 delete std::exchange(_spellHistory, nullptr);
418
421 ASSERT(m_attackers.empty());
422 ASSERT(m_sharedVision.empty());
423 ASSERT(m_Controlled.empty());
424 ASSERT(m_appliedAuras.empty());
425 ASSERT(m_ownedAuras.empty());
426 ASSERT(m_removedAuras.empty());
427 ASSERT(m_gameObj.empty());
428 ASSERT(m_dynObj.empty());
430}
431
433{
434 // WARNING! Order of execution here is important, do not change.
435 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
436 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
437 WorldObject::Update(p_time);
438
440
441 if (!IsInWorld())
442 return;
443
444 _UpdateSpells(p_time);
445
446 // If this is set during update SetCantProc(false) call is missing somewhere in the code
447 // Having this would prevent spells from being proced, so let's crash
449
450 m_combatManager.Update(p_time);
451
454 {
455 while (!extraAttacksTargets.empty())
456 {
457 auto itr = extraAttacksTargets.begin();
458 ObjectGuid targetGuid = itr->first;
459 uint32 count = itr->second;
460 extraAttacksTargets.erase(itr);
461 if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
462 HandleProcExtraAttackFor(victim, count);
463 }
465 }
466
467 // not implemented before 3.0.2
468 if (uint32 base_att = getAttackTimer(BASE_ATTACK))
469 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
470 if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
471 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
472 if (uint32 off_att = getAttackTimer(OFF_ATTACK))
473 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
474
475 // update abilities available only for fraction of time
476 UpdateReactives(p_time);
477
478 if (IsAlive())
479 {
483 }
484
485 UpdateSplineMovement(p_time);
486 i_motionMaster->Update(p_time);
487
488 // Wait with the aura interrupts until we have updated our movement generators and position
489 if (GetTypeId() == TYPEID_PLAYER)
491 else if (!movespline->Finalized())
493
494 // All position info based actions have been executed, reset info
496
499 RefreshAI();
500}
501
503{
505
506 // SMSG_FLIGHT_SPLINE_SYNC for cyclic splines
508}
509
511{
512 if (Player const* player = ToPlayer())
513 return player->GetWeaponForAttack(OFF_ATTACK, true) != nullptr;
514
515 return CanDualWield();
516}
517
518void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
519{
520 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
521 {
522 init.MoveTo(x, y, z, generatePath, forceDestination);
523 init.SetVelocity(speed);
524 };
526}
527
529{
530 if (movespline->Finalized())
531 return;
532
533 movespline->updateState(t_diff);
534 bool arrived = movespline->Finalized();
535
536 if (arrived)
537 {
539
542 }
543
545}
546
548{
550
552 {
554 pos.m_positionX = loc.x;
555 pos.m_positionY = loc.y;
556 pos.m_positionZ = loc.z;
558
559 if (TransportBase* transport = GetDirectTransport())
560 transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
561 else
562 return;
563 }
564
567
568 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
569}
570
572{
574 return;
575
577 flightSplineSync.Guid = GetGUID();
578 flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
579 SendMessageToSet(flightSplineSync.Write(), true);
580}
581
583{
584 // TODO: Check if orientation transport offset changed instead of only global orientation
587
590}
591
597
602
603bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
604{
605 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
606 return false;
607
608 float dx = GetPositionX() - obj->GetPositionX();
609 float dy = GetPositionY() - obj->GetPositionY();
610 float dz = GetPositionZ() - obj->GetPositionZ();
611 float distsq = dx * dx + dy * dy + dz * dz;
612
613 float sizefactor = GetCombatReach() + obj->GetCombatReach();
614 float maxdist = dist2compare + sizefactor;
615
616 return distsq < maxdist * maxdist;
617}
618
619bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
620{
621 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
622 return false;
623
624 float dx = pos.GetPositionX() - obj->GetPositionX();
625 float dy = pos.GetPositionY() - obj->GetPositionY();
626 float dz = pos.GetPositionZ() - obj->GetPositionZ();
627 float distsq = dx*dx + dy*dy + dz*dz;
628
629 float maxdist = GetMeleeRange(obj);
630
631 return distsq <= maxdist * maxdist;
632}
633
634float Unit::GetMeleeRange(Unit const* target) const
635{
636 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
637 return std::max(range, NOMINAL_MELEE_RANGE);
638}
639
641{
642 VisibleAuraMap::const_iterator itr = m_visibleAuras.find(slot);
643 if (itr != m_visibleAuras.end())
644 return itr->second;
645 return 0;
646}
647
649{
650 m_visibleAuras[slot]=aur;
651 UpdateAuraForGroup(slot);
652}
653
655{
656 m_visibleAuras.erase(slot);
657 UpdateAuraForGroup(slot);
658}
659
661{
662 m_interruptMask = 0;
663 for (AuraApplicationList::const_iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
664 m_interruptMask |= (*i)->GetBase()->GetSpellInfo()->AuraInterruptFlags;
665
667 if (spell->getState() == SPELL_STATE_CASTING)
668 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
669}
670
671bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag96 familyFlags) const
672{
673 if (!HasAuraType(auraType))
674 return false;
675 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
676 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
677 if (SpellInfo const* iterSpellProto = (*itr)->GetSpellInfo())
678 if (iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags & familyFlags)
679 return true;
680 return false;
681}
682
684{
685 AuraEffectList const& auras = GetAuraEffectsByType(type);
686 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
687 if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
688 ((*itr)->GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_TAKE_DAMAGE))
689 return true;
690 return false;
691}
692
693bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const
694{
695 uint32 excludeAura = 0;
696 if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : nullptr)
697 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
698
704}
705
706/*static*/ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb)
707{
708 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
709 {
710 if (absorb)
711 *absorb += damage;
712 damage = 0;
713 }
714}
715
716/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
717{
718 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
719
720 if (UnitAI* victimAI = victim->GetAI())
721 victimAI->DamageTaken(attacker, damage, damagetype, spellProto);
722
723 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
724 attackerAI->DamageDealt(victim, damage, damagetype);
725
726 // Hook for OnDamage Event
727 sScriptMgr->OnDamage(attacker, victim, damage);
728
729 // Signal to pets that their owner was attacked - except when DOT.
730 if (attacker != victim && damagetype != DOT)
731 {
732 for (Unit* controlled : victim->m_Controlled)
733 if (Creature* cControlled = controlled->ToCreature())
734 if (CreatureAI* controlledAI = cControlled->AI())
735 controlledAI->OwnerAttackedBy(attacker);
736 }
737
738 if (Player* player = victim->ToPlayer())
739 if (player->GetCommandStatus(CHEAT_GOD))
740 return 0;
741
742 if (damagetype != NODAMAGE)
743 {
744 // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
745 if (spellProto)
746 {
749 }
750 else
752
753 // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots)
754 if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
755 {
756 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
757 {
758 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
759 if (spell->getState() == SPELL_STATE_PREPARING)
760 {
761 uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
762 if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0)
763 victim->InterruptNonMeleeSpells(false);
764 }
765 }
766 }
767
768 // We're going to call functions which can modify content of the list during iteration over it's elements
769 // Let's copy the list so we can prevent iterator invalidation
771 // copy damage to casters of this aura
772 for (AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
773 {
774 // Check if aura was removed during iteration - we don't need to work on such auras
775 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
776 continue;
777 // check damage school mask
778 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
779 continue;
780
781 Unit* shareDamageTarget = (*i)->GetCaster();
782 if (!shareDamageTarget)
783 continue;
784 SpellInfo const* spell = (*i)->GetSpellInfo();
785
786 uint32 share = CalculatePct(damage, (*i)->GetAmount());
787
789 Unit::DealDamageMods(shareDamageTarget, share, nullptr);
790 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
791 }
792 }
793
794 // Rage from Damage made (only from direct weapon damage)
795 if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->GetPowerType() == POWER_RAGE)
796 {
797 uint32 weaponSpeedHitFactor;
798
799 switch (cleanDamage->attackType)
800 {
801 case BASE_ATTACK:
802 case OFF_ATTACK:
803 {
804 weaponSpeedHitFactor = uint32(attacker->GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f));
805 if (cleanDamage->hitOutCome == MELEE_HIT_CRIT)
806 weaponSpeedHitFactor *= 2;
807
808 attacker->RewardRage(rage_damage, weaponSpeedHitFactor, true);
809 break;
810 }
811 case RANGED_ATTACK:
812 break;
813 default:
814 break;
815 }
816 }
817
818 if (!damage)
819 {
820 // Rage from absorbed damage
821 if (cleanDamage && cleanDamage->absorbed_damage && victim->GetPowerType() == POWER_RAGE)
822 victim->RewardRage(cleanDamage->absorbed_damage, 0, false);
823
824 return 0;
825 }
826
827 uint32 health = victim->GetHealth();
828
829 // duel ends when player has 1 or less hp
830 bool duel_hasEnded = false;
831 bool duel_wasMounted = false;
832 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1))
833 {
834 if (!attacker)
835 return 0;
836
837 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
838 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
839 damage = health - 1;
840
841 duel_hasEnded = true;
842 }
843 else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
844 {
845 Player* victimRider = victim->GetCharmer()->ToPlayer();
846
847 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
848 {
849 if (!attacker)
850 return 0;
851
852 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
853 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
854 damage = health - 1;
855
856 duel_wasMounted = true;
857 duel_hasEnded = true;
858 }
859 }
860
861 if (attacker && attacker != victim)
862 {
863 if (Player* killer = attacker->ToPlayer())
864 {
865 // in bg, count dmg if victim is also a player
866 if (victim->GetTypeId() == TYPEID_PLAYER)
867 if (Battleground* bg = killer->GetBattleground())
868 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
869
870 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim);
871 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
872 }
873 }
874
875 if (victim->GetTypeId() == TYPEID_PLAYER)
877 else if (!victim->IsControlledByPlayer() || victim->IsVehicle())
878 {
879 if (!victim->ToCreature()->hasLootRecipient())
880 victim->ToCreature()->SetLootRecipient(attacker);
881
882 if (!attacker || attacker->IsControlledByPlayer() || (attacker->ToTempSummon() && attacker->ToTempSummon()->GetSummonerUnit() && attacker->ToTempSummon()->GetSummonerUnit()->GetTypeId() == TYPEID_PLAYER))
883 victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
884 }
885
886 if (health <= damage)
887 {
888 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
890
891 Unit::Kill(attacker, victim, durabilityLoss);
892 }
893 else
894 {
895 if (victim->GetTypeId() == TYPEID_PLAYER)
897
898 victim->ModifyHealth(-(int32)damage);
899
900 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
901 victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
902
903 if (victim->GetTypeId() != TYPEID_PLAYER)
904 {
905 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
906 if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
908
909 if (attacker)
910 victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto);
911 }
912 else // victim is a player
913 {
914 // random durability for items (HIT TAKEN)
916 {
919 }
920 }
921
922 // Rage from damage received
923 if (attacker != victim && victim->GetPowerType() == POWER_RAGE)
924 {
925 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
926 victim->RewardRage(rage_damage, 0, false);
927 }
928
929 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
930 {
931 // random durability for items (HIT DONE)
933 {
935 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
936 }
937 }
938
939 if (damagetype != NODAMAGE && damagetype != DOT && damage)
940 {
941 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC))))
942 {
943 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
944 {
945 if (spell->getState() == SPELL_STATE_PREPARING)
946 {
947 uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
948 if (interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
949 victim->InterruptNonMeleeSpells(false);
950 else
951 spell->Delayed();
952 }
953 }
954
955 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
956 if (spell->getState() == SPELL_STATE_CASTING)
957 spell->DelayedChannel();
958 }
959 }
960
961 // last damage from duel opponent
962 if (duel_hasEnded)
963 {
964 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
965
966 ASSERT_NODEBUGINFO(he && he->duel);
967
968 if (duel_wasMounted) // In this case victim == mount
969 victim->SetHealth(1);
970 else
971 he->SetHealth(1);
972
973 he->duel->Opponent->CombatStopWithPets(true);
974 he->CombatStopWithPets(true);
975
976 he->CastSpell(he, 7267, true); // beg
978 }
979 }
980
981 // make player victims stand up automatically
982 if (victim->GetStandState() && victim->IsPlayer() && damagetype != NODAMAGE && damagetype != DOT)
984
985 return damage;
986}
987
988void Unit::CastStop(uint32 except_spellid)
989{
991 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
993}
994
995void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
996{
997 if (damage < 0)
998 return;
999
1000 Unit* victim = damageInfo->target;
1001 if (!victim || !victim->IsAlive())
1002 return;
1003
1004 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1005 uint32 crTypeMask = victim->GetCreatureTypeMask();
1006
1007 // Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
1008 if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
1009 {
1010 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1011 damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, attackType);
1012
1013 // Per-school calc
1014 switch (spellInfo->DmgClass)
1015 {
1016 // Melee and Ranged Spells
1019 {
1020 if (crit)
1021 {
1022 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1023
1024 // Calculate crit bonus
1025 uint32 crit_bonus = damage;
1026 // Apply crit_damage bonus for melee spells
1027 if (Player* modOwner = GetSpellModOwner())
1028 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1029 damage += crit_bonus;
1030
1031 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1032 float critPctDamageMod = 0.0f;
1033 if (attackType == RANGED_ATTACK)
1035 else
1037
1038 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1039 critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1040
1041 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1043
1044 if (critPctDamageMod != 0)
1045 AddPct(damage, critPctDamageMod);
1046 }
1047
1048 // Spell weapon based damage CAN BE crit & blocked at same time
1049 if (blocked)
1050 {
1051 damageInfo->blocked = victim->GetShieldBlockValue();
1052 // double blocked amount if block is critical
1053 if (victim->IsBlockCritical())
1054 damageInfo->blocked += damageInfo->blocked;
1055 if (damage <= int32(damageInfo->blocked))
1056 {
1057 damageInfo->blocked = uint32(damage);
1058 damageInfo->fullBlock = true;
1059 }
1060 damage -= damageInfo->blocked;
1061 }
1062
1063 if (CanApplyResilience())
1064 Unit::ApplyResilience(victim, nullptr, &damage, crit, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
1065 break;
1066 }
1067 // Magical Attacks
1070 {
1071 // If crit add critical bonus
1072 if (crit)
1073 {
1074 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1075 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1076 }
1077
1078 if (CanApplyResilience())
1079 Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL);
1080 break;
1081 }
1082 default:
1083 break;
1084 }
1085 }
1086
1087 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1088 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
1089
1090 // Calculate absorb resist
1091 if (damage < 0)
1092 damage = 0;
1093
1094 damageInfo->damage = damage;
1096 Unit::CalcAbsorbResist(dmgInfo, spell);
1097 damageInfo->absorb = dmgInfo.GetAbsorb();
1098 damageInfo->resist = dmgInfo.GetResist();
1099
1100 if (damageInfo->absorb)
1101 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1102
1103 if (damageInfo->resist)
1104 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1105
1106 damageInfo->damage = dmgInfo.GetDamage();
1107}
1108
1109void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1110{
1111 if (!damageInfo)
1112 return;
1113
1114 Unit* victim = damageInfo->target;
1115 if (!victim)
1116 return;
1117
1118 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1119 return;
1120
1121 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID);
1122 if (spellProto == nullptr)
1123 {
1124 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo->SpellID: {}", damageInfo->SpellID);
1125 return;
1126 }
1127
1128 // Call default DealDamage
1129 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1130 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
1131}
1132
1136 damageInfo->Attacker = this;
1137 damageInfo->Target = victim;
1139 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1140 {
1141 damageInfo->Damages[i].DamageSchoolMask = GetMeleeDamageSchoolMask(attackType, i);
1142 damageInfo->Damages[i].Damage = 0;
1143 damageInfo->Damages[i].Absorb = 0;
1144 damageInfo->Damages[i].Resist = 0;
1145 }
1146
1147 damageInfo->Blocked = 0;
1148 damageInfo->HitInfo = 0;
1149 damageInfo->TargetState = 0;
1150
1151 damageInfo->AttackType = attackType;
1152 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1153 damageInfo->ProcVictim = PROC_FLAG_NONE;
1154 damageInfo->CleanDamage = 0;
1155 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1156
1157 if (!victim)
1158 return;
1159
1160 if (!IsAlive() || !victim->IsAlive())
1161 return;
1162
1163 // Select HitInfo/procAttacker/procVictim flag based on attack type
1164 switch (attackType)
1165 {
1166 case BASE_ATTACK:
1169 break;
1170 case OFF_ATTACK:
1173 damageInfo->HitInfo = HITINFO_OFFHAND;
1174 break;
1175 default:
1176 return;
1177 }
1178
1179 // Physical Immune check (must immune to all damages)
1180 uint8 immunedMask = 0;
1181 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1182 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask)))
1183 immunedMask |= (1 << i);
1184
1185 if (immunedMask == ((1 << 0) | (1 << 1)))
1186 {
1187 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1188 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1189 damageInfo->CleanDamage = 0;
1190 return;
1191 }
1192
1193 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1194 {
1195 // only players have secondary weapon damage
1196 if (i > 0 && GetTypeId() != TYPEID_PLAYER)
1197 break;
1198
1199 if (immunedMask & (1 << i))
1200 continue;
1201
1202 SpellSchoolMask schoolMask = SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask);
1203 bool const addPctMods = (schoolMask & SPELL_SCHOOL_MASK_NORMAL);
1204
1205 uint32 damage = 0;
1206 uint8 itemDamagesMask = (GetTypeId() == TYPEID_PLAYER) ? (1 << i) : 0;
1207 damage += CalculateDamage(damageInfo->AttackType, false, addPctMods, itemDamagesMask);
1208 // Add melee damage bonus
1209 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, nullptr, schoolMask);
1210 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, nullptr, schoolMask);
1211
1212 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1213 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1214
1215 // Calculate armor reduction
1217 {
1218 damageInfo->Damages[i].Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1219 damageInfo->CleanDamage += damage - damageInfo->Damages[i].Damage;
1220 }
1221 else
1222 damageInfo->Damages[i].Damage = damage;
1223 }
1224
1225 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1226
1227 switch (damageInfo->HitOutCome)
1228 {
1229 case MELEE_HIT_EVADE:
1231 damageInfo->TargetState = VICTIMSTATE_EVADES;
1232
1233 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1234 damageInfo->Damages[i].Damage = 0;
1235 damageInfo->CleanDamage = 0;
1236 return;
1237 case MELEE_HIT_MISS:
1238 damageInfo->HitInfo |= HITINFO_MISS;
1239 damageInfo->TargetState = VICTIMSTATE_INTACT;
1240
1241 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1242 damageInfo->Damages[i].Damage = 0;
1243 damageInfo->CleanDamage = 0;
1244 break;
1245 case MELEE_HIT_NORMAL:
1246 damageInfo->TargetState = VICTIMSTATE_HIT;
1247 break;
1248 case MELEE_HIT_CRIT:
1249 {
1250 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1251 damageInfo->TargetState = VICTIMSTATE_HIT;
1252
1253 // Crit bonus calc
1254 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1255 {
1256 damageInfo->Damages[i].Damage *= 2;
1257
1258 float mod = 0.0f;
1259 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1260 if (damageInfo->AttackType == RANGED_ATTACK)
1262 else
1264
1265 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1267
1268 uint32 crTypeMask = damageInfo->Target->GetCreatureTypeMask();
1269
1270 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1272 if (mod != 0)
1273 AddPct(damageInfo->Damages[i].Damage, mod);
1274 }
1275 break;
1276 }
1277 case MELEE_HIT_PARRY:
1278 damageInfo->TargetState = VICTIMSTATE_PARRY;
1279 damageInfo->CleanDamage = 0;
1280
1281 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1282 {
1283 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1284 damageInfo->Damages[i].Damage = 0;
1285 }
1286 break;
1287 case MELEE_HIT_DODGE:
1288 damageInfo->TargetState = VICTIMSTATE_DODGE;
1289 damageInfo->CleanDamage = 0;
1290
1291 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1292 {
1293 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1294 damageInfo->Damages[i].Damage = 0;
1295 }
1296 break;
1297 case MELEE_HIT_BLOCK:
1298 {
1299 damageInfo->TargetState = VICTIMSTATE_HIT;
1300 damageInfo->HitInfo |= HITINFO_BLOCK;
1301 damageInfo->Blocked = damageInfo->Target->GetShieldBlockValue();
1302 // double blocked amount if block is critical
1303 if (damageInfo->Target->IsBlockCritical())
1304 damageInfo->Blocked *= 2;
1305
1306 uint32 remainingBlock = damageInfo->Blocked;
1307 uint8 fullBlockMask = 0;
1308 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1309 {
1310 if (remainingBlock && remainingBlock >= damageInfo->Damages[i].Damage)
1311 {
1312 fullBlockMask |= (1 << i);
1313
1314 remainingBlock -= damageInfo->Damages[i].Damage;
1315 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1316 damageInfo->Damages[i].Damage = 0;
1317 }
1318 else
1319 {
1320 damageInfo->CleanDamage += remainingBlock;
1321 damageInfo->Damages[i].Damage -= remainingBlock;
1322 remainingBlock = 0;
1323 }
1324 }
1325
1326 // full block
1327 if (fullBlockMask == ((1 << 0) | (1 << 1)))
1328 {
1329 damageInfo->TargetState = VICTIMSTATE_BLOCKS;
1330 damageInfo->Blocked -= remainingBlock;
1331 }
1332 break;
1333 }
1334 case MELEE_HIT_GLANCING:
1335 {
1336 damageInfo->HitInfo |= HITINFO_GLANCING;
1337 damageInfo->TargetState = VICTIMSTATE_HIT;
1338 int32 leveldif = int32(victim->GetLevelForTarget(this)) - int32(GetLevel());
1339 if (leveldif < 0)
1340 {
1341 TC_LOG_DEBUG("entities.unit", "Unit::CalculateMeleeDamage: (Player) {} attacked {}. Glancing should never happen against lower level target", GetGUID().ToString(), victim->GetGUID().ToString());
1342 break;
1343 }
1344 if (leveldif == 0)
1345 leveldif = 1;
1346 if (leveldif > 3)
1347 leveldif = 3;
1348
1349 // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
1350 // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
1351 int32 const reductionMax = leveldif * 10;
1352 int32 const reductionMin = std::max(1, reductionMax - 10);
1353
1354 float reducePercent = 1.f - irand(reductionMin, reductionMax) / 100.0f;
1355
1356 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1357 {
1358 uint32 reducedDamage = uint32(reducePercent * damageInfo->Damages[i].Damage);
1359 damageInfo->CleanDamage += damageInfo->Damages[i].Damage - reducedDamage;
1360 damageInfo->Damages[i].Damage = reducedDamage;
1361 }
1362 break;
1363 }
1364 case MELEE_HIT_CRUSHING:
1365 damageInfo->HitInfo |= HITINFO_CRUSHING;
1366 damageInfo->TargetState = VICTIMSTATE_HIT;
1367
1368 // 150% normal damage
1369 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1370 damageInfo->Damages[i].Damage += (damageInfo->Damages[i].Damage / 2);
1371 break;
1372 default:
1373 break;
1374 }
1375
1376 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1377 if (!(damageInfo->HitInfo & HITINFO_MISS))
1378 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1379
1380 uint32 tmpHitInfo[MAX_ITEM_PROTO_DAMAGES] = { };
1381
1382 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1383 {
1384 int32 resilienceReduction = damageInfo->Damages[i].Damage;
1385 // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here
1386 if (CanApplyResilience())
1387 Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->HitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
1388 resilienceReduction = damageInfo->Damages[i].Damage - resilienceReduction;
1389 damageInfo->Damages[i].Damage -= resilienceReduction;
1390 damageInfo->CleanDamage += resilienceReduction;
1391
1392 // Calculate absorb resist
1393 if (int32(damageInfo->Damages[i].Damage) > 0)
1394 {
1395 damageInfo->ProcVictim |= PROC_FLAG_TAKEN_DAMAGE;
1396 // Calculate absorb & resists
1397 DamageInfo dmgInfo(*damageInfo, i);
1398 Unit::CalcAbsorbResist(dmgInfo);
1399 damageInfo->Damages[i].Absorb = dmgInfo.GetAbsorb();
1400 damageInfo->Damages[i].Resist = dmgInfo.GetResist();
1401
1402 if (damageInfo->Damages[i].Absorb)
1403 tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1404
1405 if (damageInfo->Damages[i].Resist)
1406 tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1407
1408 damageInfo->CleanDamage += damageInfo->Damages[i].Damage - dmgInfo.GetDamage();
1409 damageInfo->Damages[i].Damage = dmgInfo.GetDamage();
1410 }
1411 else // Impossible get negative result but....
1412 damageInfo->Damages[i].Damage = 0;
1413 }
1414
1415 // set proper HitInfo flags
1416 if ((tmpHitInfo[0] & HITINFO_FULL_ABSORB) != 0)
1417 {
1418 // set partial absorb when secondary damage isn't full absorbed
1419 damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_ABSORB) != 0) ? HITINFO_PARTIAL_ABSORB : HITINFO_FULL_ABSORB;
1420 }
1421 else
1422 damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_ABSORB);
1423
1424 if ((tmpHitInfo[0] & HITINFO_FULL_RESIST) != 0)
1425 {
1426 // set partial resist when secondary damage isn't full resisted
1427 damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_RESIST) != 0) ? HITINFO_PARTIAL_RESIST : HITINFO_FULL_RESIST;
1428 }
1429 else
1430 damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_RESIST);
1431}
1432
1433void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1434{
1435 Unit* victim = damageInfo->Target;
1436
1437 auto canTakeMeleeDamage = [&]()
1438 {
1439 return victim->IsAlive() && !victim->HasUnitState(UNIT_STATE_IN_FLIGHT) && (victim->GetTypeId() != TYPEID_UNIT || !victim->ToCreature()->IsEvadingAttacks());
1440 };
1441
1442 if (!canTakeMeleeDamage())
1443 return;
1444
1445 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1447 {
1448 // Get attack timers
1449 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1450 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1451 // Reduce attack time
1452 if (victim->haveOffhandWeapon() && offtime < basetime)
1453 {
1454 float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
1455 float percent60 = 3.0f * percent20;
1456 if (offtime > percent20 && offtime <= percent60)
1457 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1458 else if (offtime > percent60)
1459 {
1460 offtime -= 2.0f * percent20;
1461 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1462 }
1463 }
1464 else
1465 {
1466 float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20f;
1467 float percent60 = 3.0f * percent20;
1468 if (basetime > percent20 && basetime <= percent60)
1469 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1470 else if (basetime > percent60)
1471 {
1472 basetime -= 2.0f * percent20;
1473 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1474 }
1475 }
1476 }
1477
1478 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1479 {
1480 if (!canTakeMeleeDamage() || (!damageInfo->Damages[i].Damage && !damageInfo->Damages[i].Absorb && !damageInfo->Damages[i].Resist))
1481 continue;
1482
1483 // Call default DealDamage
1484 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Damages[i].Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1485 Unit::DealDamage(this, victim, damageInfo->Damages[i].Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask), nullptr, durabilityLoss);
1486 }
1487
1488 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1489 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1490 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1491 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1492 {
1493 // 20% base chance
1494 float chance = 20.0f;
1495
1496 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1497 if (victim->GetLevel() < 30)
1498 chance = 0.65f * victim->GetLevel() + 0.5f;
1499
1500 uint32 const victimDefense = victim->GetDefenseSkillValue();
1501 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1502
1503 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1504
1505 // -probability is between 0% and 40%
1506 RoundToInterval(chance, 0.0f, 40.0f);
1507 if (roll_chance_f(chance))
1508 CastSpell(victim, 1604 /*SPELL_DAZED*/, true);
1509 }
1510
1511 if (GetTypeId() == TYPEID_PLAYER)
1512 {
1513 DamageInfo dmgInfo(*damageInfo);
1514 ToPlayer()->CastItemCombatSpell(dmgInfo);
1515 }
1516
1517 // Do effect if any damage done to target
1518 if (damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage)
1519 {
1520 // We're going to call functions which can modify content of the list during iteration over it's elements
1521 // Let's copy the list so we can prevent iterator invalidation
1523 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1524 {
1525 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1526
1527 // Damage shield can be resisted...
1528 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
1529 if (missInfo != SPELL_MISS_NONE)
1530 {
1531 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1532 continue;
1533 }
1534
1535 // ...or immuned
1536 if (IsImmunedToDamage(spellInfo))
1537 {
1538 victim->SendSpellDamageImmune(this, spellInfo->Id);
1539 continue;
1540 }
1541
1542 uint32 damage = aurEff->GetAmount();
1543 if (Unit* caster = aurEff->GetCaster())
1544 {
1545 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo(), { });
1546 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1547 }
1548
1549 // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
1550 Unit::DealDamageMods(this, damage, nullptr);
1551
1553 WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4);
1554 data << victim->GetGUID();
1555 data << GetGUID();
1556 data << uint32(spellInfo->Id);
1557 data << uint32(damage); // Damage
1558 int32 const overkill = int32(damage) - int32(GetHealth());
1559 data << uint32(std::max(overkill, 0)); // Overkill
1560 data << uint32(spellInfo->SchoolMask);
1561 victim->SendMessageToSet(&data, true);
1562
1563 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1564 }
1565 }
1566}
1567
1569{
1571 packet.EmoteID = emoteId;
1572 packet.Guid = GetGUID();
1573 SendMessageToSet(packet.Write(), true);
1574}
1575
1576/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1577{
1578 // only physical spells damage gets reduced by armor
1579 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1580 return false;
1581
1582 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1583}
1584
1585/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1586{
1587 float armor = float(victim->GetArmor());
1588
1589 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1590 if (attacker)
1591 {
1593
1594 if (spellInfo)
1595 if (Player* modOwner = attacker->GetSpellModOwner())
1596 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
1597
1599 for (AuraEffect const* aurEff : resIgnoreAurasAb)
1600 {
1601 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1602 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1603 }
1604
1606 for (AuraEffect const* aurEff : resIgnoreAuras)
1607 {
1608 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
1609 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1610 }
1611
1612 // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
1613 if (attacker->GetTypeId() == TYPEID_PLAYER)
1614 {
1615 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1616
1617 Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
1618 arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
1619 {
1620 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
1621 });
1622
1623 // no more than 100%
1624 RoundToInterval(arpPct, 0.f, 100.f);
1625
1626 float maxArmorPen = 0.f;
1627 if (victim->GetLevel() < 60)
1628 maxArmorPen = float(400 + 85 * victim->GetLevel());
1629 else
1630 maxArmorPen = 400 + 85 * victim->GetLevel() + 4.5f * 85 * (victim->GetLevel() - 59);
1631
1632 // Cap armor penetration to this number
1633 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1634 // Figure out how much armor do we ignore
1635 armor -= CalculatePct(maxArmorPen, arpPct);
1636 }
1637 }
1638
1639 if (armor < 0.0f)
1640 armor = 0.0f;
1641
1642 float levelModifier = attacker ? attacker->GetLevel() : attackerLevel;
1643 if (levelModifier > 59.f)
1644 levelModifier = levelModifier + 4.5f * (levelModifier - 59.f);
1645
1646 float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40.f);
1647 damageReduction /= (1.0f + damageReduction);
1648
1649 RoundToInterval(damageReduction, 0.f, 0.75f);
1650 return uint32(std::ceil(std::max(damage * (1.0f - damageReduction), 0.0f)));
1651}
1652
1653/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1654{
1655 // Magic damage, check for resists
1656 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1657 return 0;
1658
1659 // Npcs can have holy resistance
1660 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1661 return 0;
1662
1663 // Ignore spells that can't be resisted
1664 if (spellInfo)
1665 {
1667 return 0;
1668 }
1669
1670 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1671 float discreteResistProbability[11] = { };
1672 if (averageResist <= 0.1f)
1673 {
1674 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1675 discreteResistProbability[1] = 5.0f * averageResist;
1676 discreteResistProbability[2] = 2.5f * averageResist;
1677 }
1678 else
1679 {
1680 for (uint32 i = 0; i < 11; ++i)
1681 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1682 }
1683
1684 float roll = float(rand_norm());
1685 float probabilitySum = 0.0f;
1686
1687 uint32 resistance = 0;
1688 for (; resistance < 11; ++resistance)
1689 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1690 break;
1691
1692 float damageResisted = damage * resistance / 10.f;
1693 if (damageResisted > 0.0f) // if any damage was resisted
1694 {
1695 int32 ignoredResistance = 0;
1696 if (attacker)
1697 {
1698 ignoredResistance += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
1699 {
1700 if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectingSpell(spellInfo))
1701 return true;
1702 return false;
1703 });
1704
1705 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1706 }
1707
1708 ignoredResistance = std::min<int32>(ignoredResistance, 100);
1709 ApplyPct(damageResisted, 100 - ignoredResistance);
1710
1711 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1712 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1713 {
1714 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1715 float armorReduction = damage - damageAfterArmor;
1716
1717 // pick the lower one, the weakest resistance counts
1718 damageResisted = std::min(damageResisted, armorReduction);
1719 }
1720 }
1721
1722 damageResisted = std::max(damageResisted, 0.f);
1723 return uint32(damageResisted);
1724}
1725
1726/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo)
1727{
1728 float victimResistance = float(victim->GetResistance(schoolMask));
1729 if (caster)
1730 {
1731 // pets inherit 100% of masters penetration
1732 if (Player const* player = caster->GetSpellModOwner())
1733 {
1734 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1735 victimResistance -= float(player->GetSpellPenetrationItemMod());
1736 }
1737 else if (Unit const* unitCaster = caster->ToUnit())
1738 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1739 }
1740
1741 // holy resistance exists in pve and comes from level difference, ignore template values
1742 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1743 victimResistance = 0.0f;
1744
1745 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1746 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->SpellIconID == 3178)
1747 victimResistance = 0.0f;
1748
1749 victimResistance = std::max(victimResistance, 0.0f);
1750
1751 // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
1752 // gameobject caster -- should it have level based resistance?
1753 if (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
1754 victimResistance += std::max((float(victim->GetLevelForTarget(caster)) - float(caster->GetLevelForTarget(victim))) * 5.0f, 0.0f);
1755
1756 static uint32 const BOSS_LEVEL = 83;
1757 static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
1758 uint32 level = victim->GetLevel();
1759 float resistanceConstant = 0.0f;
1760
1761 if (level == BOSS_LEVEL)
1762 resistanceConstant = BOSS_RESISTANCE_CONSTANT;
1763 else
1764 resistanceConstant = level * 5.0f;
1765
1766 return victimResistance / (victimResistance + resistanceConstant);
1767}
1768
1769/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1770{
1771 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1772 return;
1773
1774 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1775
1776 // Ignore Absorption Auras
1777 float auraAbsorbMod = 0.f;
1778 if (Unit* attacker = damageInfo.GetAttacker())
1779 {
1780 auraAbsorbMod = attacker->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask());
1781 auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(attacker->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool
1782 {
1783 if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1784 return false;
1785
1786 if (!aurEff->IsAffectingSpell(damageInfo.GetSpellInfo()))
1787 return false;
1788
1789 return true;
1790 })));
1791 }
1792
1793 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1794
1795 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1796
1797 if (spell)
1798 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1799
1800 damageInfo.ResistDamage(resistedDamage);
1801 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1802
1803 // We're going to call functions which can modify content of the list during iteration over it's elements
1804 // Let's copy the list so we can prevent iterator invalidation
1806 vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
1807
1808 // absorb without mana cost
1809 for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1810 {
1811 AuraEffect* absorbAurEff = *itr;
1812 // Check if aura was removed during iteration - we don't need to work on such auras
1813 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1814 if (!aurApp)
1815 continue;
1816 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1817 continue;
1818
1819 // get amount which can be still absorbed by the aura
1820 int32 currentAbsorb = absorbAurEff->GetAmount();
1821 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1822 if (currentAbsorb < 0)
1823 currentAbsorb = 0;
1824
1825 uint32 tempAbsorb = uint32(currentAbsorb);
1826
1827 bool defaultPrevented = false;
1828
1829 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1830 currentAbsorb = tempAbsorb;
1831
1832 if (defaultPrevented)
1833 continue;
1834
1835 // absorb must be smaller than the damage itself
1836 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1837
1838 damageInfo.AbsorbDamage(currentAbsorb);
1839
1840 tempAbsorb = currentAbsorb;
1841 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1842
1843 // Check if our aura is using amount to count damage
1844 if (absorbAurEff->GetAmount() >= 0)
1845 {
1846 // Reduce shield amount
1847 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1848 // Aura cannot absorb anything more - remove it
1849 if (absorbAurEff->GetAmount() <= 0)
1850 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1851 }
1852 }
1853
1854 // absorb by mana cost
1856 for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1857 {
1858 AuraEffect* absorbAurEff = *itr;
1859 // Check if aura was removed during iteration - we don't need to work on such auras
1860 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1861 if (!aurApp)
1862 continue;
1863 // check damage school mask
1864 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1865 continue;
1866
1867 // get amount which can be still absorbed by the aura
1868 int32 currentAbsorb = absorbAurEff->GetAmount();
1869 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1870 if (currentAbsorb < 0)
1871 currentAbsorb = 0;
1872
1873 uint32 tempAbsorb = currentAbsorb;
1874
1875 bool defaultPrevented = false;
1876
1877 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1878 currentAbsorb = tempAbsorb;
1879
1880 if (defaultPrevented)
1881 continue;
1882
1883 // absorb must be smaller than the damage itself
1884 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1885
1886 int32 manaReduction = currentAbsorb;
1887
1888 // lower absorb amount by talents
1889 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
1890 manaReduction = int32(float(manaReduction) * manaMultiplier);
1891
1892 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
1893
1894 // take case when mana has ended up into account
1895 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
1896
1897 damageInfo.AbsorbDamage(currentAbsorb);
1898
1899 tempAbsorb = currentAbsorb;
1900 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1901
1902 // Check if our aura is using amount to count damage
1903 if (absorbAurEff->GetAmount() >= 0)
1904 {
1905 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1906 if ((absorbAurEff->GetAmount() <= 0))
1907 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1908 }
1909 }
1910
1911 damageInfo.ModifyDamage(absorbIgnoringDamage);
1912
1913 // split damage auras - only when not damaging self
1914 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
1915 {
1916 // We're going to call functions which can modify content of the list during iteration over it's elements
1917 // Let's copy the list so we can prevent iterator invalidation
1919 for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1920 {
1921 // Check if aura was removed during iteration - we don't need to work on such auras
1922 if (!((*itr)->GetBase()->IsAppliedOnTarget(damageInfo.GetVictim()->GetGUID())))
1923 continue;
1924 // check damage school mask
1925 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
1926 continue;
1927
1928 // Damage can be splitted only if aura has an alive caster
1929 Unit* caster = (*itr)->GetCaster();
1930 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
1931 continue;
1932
1933 int32 splitDamage = (*itr)->GetAmount();
1934
1935 // absorb must be smaller than the damage itself
1936 splitDamage = RoundToInterval(splitDamage, 0, int32(damageInfo.GetDamage()));
1937
1938 damageInfo.AbsorbDamage(splitDamage);
1939
1940 // check if caster is immune to damage
1941 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
1942 {
1943 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
1944 continue;
1945 }
1946
1947 uint32 splitted = splitDamage;
1948 uint32 splitted_absorb = 0;
1949 Unit::DealDamageMods(caster, splitted, &splitted_absorb);
1950
1951 if (Unit* attacker = damageInfo.GetAttacker())
1952 attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, damageInfo.GetDamageType() == DOT, 0, false, true);
1953
1954 CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
1955 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
1956 }
1957
1958 // We're going to call functions which can modify content of the list during iteration over it's elements
1959 // Let's copy the list so we can prevent iterator invalidation
1961 for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
1962 {
1963 // Check if aura was removed during iteration - we don't need to work on such auras
1964 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1965 if (!aurApp)
1966 continue;
1967
1968 // check damage school mask
1969 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
1970 continue;
1971
1972 // Damage can be splitted only if aura has an alive caster
1973 Unit* caster = (*itr)->GetCaster();
1974 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
1975 continue;
1976
1977 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
1978
1979 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
1980
1981 // absorb must be smaller than the damage itself
1982 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
1983
1984 damageInfo.AbsorbDamage(splitDamage);
1985
1986 // check if caster is immune to damage
1987 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
1988 {
1989 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
1990 continue;
1991 }
1992
1993 uint32 split_absorb = 0;
1994 Unit::DealDamageMods(caster, splitDamage, &split_absorb);
1995
1996 if (Unit* attacker = damageInfo.GetAttacker())
1997 attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, damageInfo.GetDamageType() == DOT, 0, false, true);
1998
1999 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2000 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2001
2002 // break 'Fear' and similar auras
2004 }
2005 }
2006}
2007
2008/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2009{
2010 if (!healInfo.GetHeal())
2011 return;
2012
2013 int32 const healing = static_cast<int32>(healInfo.GetHeal());
2014 int32 absorbAmount = 0;
2015
2016 // Need remove expired auras after
2017 bool existExpired = false;
2018
2019 // absorb without mana cost
2021 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && absorbAmount <= healing; ++i)
2022 {
2023 if (!((*i)->GetMiscValue() & healInfo.GetSpellInfo()->SchoolMask))
2024 continue;
2025
2026 // Max Amount can be absorbed by this aura
2027 int32 currentAbsorb = (*i)->GetAmount();
2028
2029 // Found empty aura (impossible but..)
2030 if (currentAbsorb <= 0)
2031 {
2032 existExpired = true;
2033 continue;
2034 }
2035
2036 // currentAbsorb - damage can be absorbed by shield
2037 // If need absorb less damage
2038 if (healing < currentAbsorb + absorbAmount)
2039 currentAbsorb = healing - absorbAmount;
2040
2041 absorbAmount += currentAbsorb;
2042
2043 // Reduce shield amount
2044 (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
2045 // Need remove it later
2046 if ((*i)->GetAmount() <= 0)
2047 existExpired = true;
2048 }
2049
2050 // Remove all expired absorb auras
2051 if (existExpired)
2052 {
2053 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();)
2054 {
2055 AuraEffect* auraEff = *i;
2056 ++i;
2057 if (auraEff->GetAmount() <= 0)
2058 {
2059 uint32 removedAuras = healInfo.GetTarget()->m_removedAurasCount;
2061 if (removedAuras + 1 < healInfo.GetTarget()->m_removedAurasCount)
2062 i = vHealAbsorb.begin();
2063 }
2064 }
2065 }
2066
2067 if (absorbAmount > 0)
2068 healInfo.AbsorbHeal(absorbAmount);
2069}
2070
2071void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2072{
2074 return;
2075
2077 return;
2078
2079 if (!victim->IsAlive())
2080 return;
2081
2082 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2083 return;
2084
2085 AtTargetAttacked(victim, true);
2087
2088 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2089 return; // ignore ranged case
2090
2091 if (!extra && _lastExtraAttackSpell)
2093
2094 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2095 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2097 else
2098 {
2099 // attack can be redirected to another target
2100 victim = GetMeleeHitRedirectTarget(victim);
2101
2102 CalcDamageInfo damageInfo;
2103 CalculateMeleeDamage(victim, &damageInfo, attType);
2104 // Send log damage message to client
2105
2106 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
2107 Unit::DealDamageMods(victim, damageInfo.Damages[i].Damage, &damageInfo.Damages[i].Absorb);
2108 SendAttackStateUpdate(&damageInfo);
2109
2110 _lastDamagedTargetGuid = victim->GetGUID();
2111
2112 DealMeleeDamage(&damageInfo, true);
2113
2114 DamageInfo dmgInfo(damageInfo);
2115 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2116
2117 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2118 GetGUID().ToString(), victim->GetGUID().ToString(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist());
2119 }
2120}
2121
2123{
2124 while (count)
2125 {
2126 --count;
2127 AttackerStateUpdate(victim, BASE_ATTACK, true);
2128 }
2129}
2130
2132{
2134 if (!targetGUID)
2135 {
2136 ObjectGuid selection = GetTarget();
2137 if (!selection.IsEmpty())
2138 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2139 else
2140 return;
2141 }
2142
2143 extraAttacksTargets[targetGUID] += count;
2144}
2145
2147{
2148 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
2149 return MELEE_HIT_EVADE;
2150
2151 int32 const attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
2152 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2153
2154 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2155 int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this);
2156
2157 // Miss chance based on melee
2158 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, attackerWeaponSkill - victimMaxSkillValueForLevel, 0) * 100.0f);
2159
2160 // Critical hit chance
2161 int32 crit_chance = int32(GetUnitCriticalChanceAgainst(attType, victim) * 100.0f);
2162
2163 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2164 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2165 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2166
2167 // melee attack table implementation
2168 // outcome priority:
2169 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2170 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2171
2172 int32 sum = 0, tmp = 0;
2173 int32 roll = urand(0, 9999);
2174
2175 // check if attack comes from behind, nobody can parry or block if attacker is behind
2176 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2177
2178 // only creatures can dodge if attacker is behind
2179 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2180
2181 // if victim is casting or cc'd it can't avoid attacks
2182 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2183 {
2184 canDodge = false;
2185 canParryOrBlock = false;
2186 }
2187
2188 // 1. MISS
2189 tmp = miss_chance;
2190 if (tmp > 0 && roll < (sum += tmp))
2191 return MELEE_HIT_MISS;
2192
2193 // always crit against a sitting target (except 0 crit chance)
2194 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2195 return MELEE_HIT_CRIT;
2196
2197 // 2. DODGE
2198 if (canDodge)
2199 {
2200 tmp = dodge_chance;
2201 if (tmp > 0 // check if unit _can_ dodge
2202 && roll < (sum += tmp))
2203 return MELEE_HIT_DODGE;
2204 }
2205
2206 // 3. PARRY
2207 if (canParryOrBlock)
2208 {
2209 tmp = parry_chance;
2210 if (tmp > 0 // check if unit _can_ parry
2211 && roll < (sum += tmp))
2212 return MELEE_HIT_PARRY;
2213 }
2214
2215 // 4. GLANCING
2216 // Max 40% chance to score a glancing blow against mobs of the same or higher level (only players and pets, not for ranged weapons).
2217 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2218 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2219 GetLevel() <= victim->GetLevelForTarget(this))
2220 {
2221 // cap possible value (with bonuses > max skill)
2222 int32 skill = attackerWeaponSkill;
2223 int32 maxskill = attackerMaxSkillValueForLevel;
2224 skill = (skill > maxskill) ? maxskill : skill;
2225
2226 // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
2227 // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
2228 tmp = 600 + (victimDefenseSkill - skill) * 120;
2229 tmp = std::min(tmp, 4000);
2230 if (tmp > 0 && roll < (sum += tmp))
2231 return MELEE_HIT_GLANCING;
2232 }
2233
2234 // 5. BLOCK
2235 if (canParryOrBlock)
2236 {
2237 tmp = block_chance;
2238 if (tmp > 0 // check if unit _can_ block
2239 && roll < (sum += tmp))
2240 return MELEE_HIT_BLOCK;
2241 }
2242
2243 // 6.CRIT
2244 tmp = crit_chance;
2245 if (tmp > 0 && roll < (sum += tmp))
2246 return MELEE_HIT_CRIT;
2247
2248 // 7. CRUSHING
2249 // mobs can score crushing blows if they're 4 or more levels above victim
2250 if (GetLevelForTarget(victim) >= victim->GetLevelForTarget(this) + 4 &&
2251 // can be from by creature (if can) or from controlled player that considered as creature
2253 !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS))
2254 {
2255 // when their weapon skill is 15 or more above victim's defense skill
2256 tmp = victimDefenseSkill;
2257 // having defense above your maximum (from items, talents etc.) has no effect
2258 tmp = std::min(tmp, victimMaxSkillValueForLevel);
2259 // tmp = mob's level * 5 - player's current defense skill
2260 tmp = attackerMaxSkillValueForLevel - tmp;
2261 // minimum of 20 points diff (4 levels difference)
2262 tmp = std::max(tmp, 20);
2263
2264 // add 2% chance per lacking skill point
2265 tmp = tmp * 200 - 1500;
2266 if (tmp > 0 && roll < (sum += tmp))
2267 return MELEE_HIT_CRUSHING;
2268 }
2269
2270 // 8. HIT
2271 return MELEE_HIT_NORMAL;
2272}
2273
2274uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask /*= 0*/) const
2275{
2276 float minDamage = 0.0f;
2277 float maxDamage = 0.0f;
2278
2279 if (normalized || !addTotalPct || itemDamagesMask)
2280 {
2281 // get both by default
2282 if (!itemDamagesMask)
2283 itemDamagesMask = (1 << 0) | (1 << 1);
2284
2285 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
2286 {
2287 if (itemDamagesMask & (1 << i))
2288 {
2289 float minTmp, maxTmp;
2290 CalculateMinMaxDamage(attType, normalized, addTotalPct, minTmp, maxTmp, i);
2291 minDamage += minTmp;
2292 maxDamage += maxTmp;
2293 }
2294 }
2295 }
2296 else
2297 {
2298 switch (attType)
2299 {
2300 case RANGED_ATTACK:
2303 break;
2304 case BASE_ATTACK:
2307 break;
2308 case OFF_ATTACK:
2311 break;
2312 default:
2313 break;
2314 }
2315 }
2316
2317 minDamage = std::max(0.f, minDamage);
2318 maxDamage = std::max(0.f, maxDamage);
2319
2320 if (minDamage > maxDamage)
2321 std::swap(minDamage, maxDamage);
2322
2323 return urand(uint32(minDamage), uint32(maxDamage));
2324}
2325
2327{
2328 if (!spellInfo->MaxLevel || GetLevel() < spellInfo->MaxLevel)
2329 return 1.0f;
2330
2331 return std::max(0.0f, std::min(1.0f, (22.0f + spellInfo->MaxLevel - GetLevel()) / 20.0f));
2332}
2333
2335{
2337 packet.Attacker = GetGUID();
2338 packet.Victim = victim->GetGUID();
2339 SendMessageToSet(packet.Write(), true);
2340}
2341
2343{
2344 SendMessageToSet(WorldPackets::Combat::SAttackStop(this, victim).Write(), true);
2345
2346 if (victim)
2347 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2348 else
2349 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2350}
2351
2353{
2355 return true;
2356 return false;
2357}
2358
2360{
2361 if (!spellInfo)
2362 return 0;
2363
2364 int32 resistMech = 0;
2365 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2366 {
2367 if (!effect.IsEffect())
2368 break;
2369
2370 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2371 if (effectMech)
2372 {
2374 if (resistMech < temp)
2375 resistMech = temp;
2376 }
2377 }
2378
2379 return std::max(resistMech, 0);
2380}
2381
2382bool Unit::CanUseAttackType(uint8 attacktype) const
2383{
2384 switch (attacktype)
2385 {
2386 case BASE_ATTACK:
2388 case OFF_ATTACK:
2390 case RANGED_ATTACK:
2392 default:
2393 return true;
2394 }
2395}
2396
2397// Melee based spells hit result calculations
2399{
2400 WeaponAttackType attType = BASE_ATTACK;
2401
2402 // Check damage class instead of attack type to correctly handle judgements
2403 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2404 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2405 attType = RANGED_ATTACK;
2406
2407 int32 attackerWeaponSkill;
2408 // skill value for these spells (for example judgements) is 5 * level
2409 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spellInfo->IsRangedWeaponSpell())
2410 attackerWeaponSkill = GetMaxSkillValueForLevel();
2411 else
2412 attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
2413
2414 int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
2415
2416 uint32 roll = urand(0, 9999);
2417
2418 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spellInfo->Id) * 100.0f);
2419 // Roll miss
2420 uint32 tmp = missChance;
2421 if (roll < tmp)
2422 return SPELL_MISS_MISS;
2423
2424 // Chance resist mechanic
2425 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2426 tmp += resist_chance;
2427 if (roll < tmp)
2428 return SPELL_MISS_RESIST;
2429
2430 // Same spells cannot be parried/dodged
2432 return SPELL_MISS_NONE;
2433
2434 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_DODGE);
2435 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_PARRY);
2436 bool canBlock = true; // all melee and ranged attacks can be blocked
2437
2438 // if victim is casting or cc'd it can't avoid attacks
2439 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2440 {
2441 canDodge = false;
2442 canParry = false;
2443 canBlock = false;
2444 }
2445
2446 // Ranged attacks can only miss, resist and deflect and get blocked
2447 if (attType == RANGED_ATTACK)
2448 {
2449 canParry = false;
2450 canDodge = false;
2451
2452 // only if in front
2453 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2454 {
2455 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
2456 tmp += deflect_chance;
2457 if (roll < tmp)
2458 return SPELL_MISS_DEFLECT;
2459 }
2460 }
2461
2462 // Check for attack from behind
2463 if (!victim->HasInArc(float(M_PI), this))
2464 {
2466 {
2467 // Can't dodge from behind in PvP (but its possible in PvE)
2468 if (victim->GetTypeId() == TYPEID_PLAYER)
2469 canDodge = false;
2470 // Can't parry or block
2471 canParry = false;
2472 canBlock = false;
2473 }
2474 else // Only deterrence as of 3.3.5
2475 {
2477 canParry = false;
2478 }
2479 }
2480
2481 // Ignore combat result aura
2483 for (AuraEffect const* aurEff : ignore)
2484 {
2485 if (!aurEff->IsAffectingSpell(spellInfo))
2486 continue;
2487
2488 switch (aurEff->GetMiscValue())
2489 {
2490 case MELEE_HIT_DODGE:
2491 canDodge = false;
2492 break;
2493 case MELEE_HIT_BLOCK:
2494 canBlock = false;
2495 break;
2496 case MELEE_HIT_PARRY:
2497 canParry = false;
2498 break;
2499 default:
2500 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2501 break;
2502 }
2503 }
2504
2505 if (canDodge)
2506 {
2507 // Roll dodge
2508 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2509 if (dodgeChance < 0)
2510 dodgeChance = 0;
2511
2512 if (roll < (tmp += dodgeChance))
2513 return SPELL_MISS_DODGE;
2514 }
2515
2516 if (canParry)
2517 {
2518 // Roll parry
2519 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2520 if (parryChance < 0)
2521 parryChance = 0;
2522
2523 tmp += parryChance;
2524 if (roll < tmp)
2525 return SPELL_MISS_PARRY;
2526 }
2527
2528 if (canBlock)
2529 {
2530 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2531 if (blockChance < 0)
2532 blockChance = 0;
2533 tmp += blockChance;
2534
2535 if (roll < tmp)
2536 return SPELL_MISS_BLOCK;
2537 }
2538
2539 return SPELL_MISS_NONE;
2540}
2541
2543{
2544 uint32 value = GetShieldBlockValue();
2545 if (value >= hard_cap)
2546 {
2547 value = (soft_cap + hard_cap) / 2;
2548 }
2549 else if (value > soft_cap)
2550 {
2551 value = soft_cap + ((value - soft_cap) / 2);
2552 }
2553
2554 return value;
2555}
2556
2558{
2559 if (GetTypeId() == TYPEID_PLAYER)
2560 {
2561 // in PvP use full skill instead current skill value
2562 uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
2565 value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
2566 return value;
2567 }
2568 else
2569 return GetMaxSkillValueForLevel(target);
2570}
2571
2572float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2573{
2574 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2575 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2576 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2577
2578 float chance = 0.0f;
2579 float skillBonus = 0.0f;
2580 if (victim->GetTypeId() == TYPEID_PLAYER)
2581 {
2582 chance = victim->GetFloatValue(PLAYER_DODGE_PERCENTAGE);
2583 skillBonus = 0.04f * skillDiff;
2584 }
2585 else
2586 {
2587 if (!victim->IsTotem())
2588 {
2589 chance = 5.0f;
2591
2592 if (skillDiff <= 10)
2593 skillBonus = skillDiff * 0.1f;
2594 else
2595 skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
2596 }
2597 }
2598
2599 chance += skillBonus;
2600
2601 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2603
2604 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2606
2607 // Reduce dodge chance by attacker expertise rating
2608 if (GetTypeId() == TYPEID_PLAYER)
2609 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2610 else
2612 return std::max(chance, 0.0f);
2613}
2614
2615float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2616{
2617 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2618 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2619 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2620
2621 float chance = 0.0f;
2622 float skillBonus = 0.0f;
2623 if (Player const* playerVictim = victim->ToPlayer())
2624 {
2625 if (playerVictim->CanParry())
2626 {
2627 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2628 if (!tmpitem)
2629 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2630
2631 if (tmpitem)
2632 chance = playerVictim->GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2633
2634 skillBonus = 0.04f * skillDiff;
2635 }
2636 }
2637 else
2638 {
2640 {
2641 chance = 5.0f;
2643
2644 if (skillDiff <= 10)
2645 skillBonus = skillDiff * 0.1f;
2646 else
2647 skillBonus = 1.0f + (skillDiff - 10) * 1.6f;
2648 }
2649 }
2650
2651 chance += skillBonus;
2652
2653 // Reduce parry chance by attacker expertise rating
2654 if (GetTypeId() == TYPEID_PLAYER)
2655 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2656 else
2658 return std::max(chance, 0.0f);
2659}
2660
2662{
2663 float miss_chance = 5.0f;
2664
2665 if (Player const* player = ToPlayer())
2666 miss_chance += player->GetMissPercentageFromDefense();
2667
2668 return miss_chance;
2669}
2670
2671float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const
2672{
2673 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2674 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2675 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2676
2677 float chance = 0.0f;
2678 float skillBonus = 0.0f;
2679 if (Player const* playerVictim = victim->ToPlayer())
2680 {
2681 if (playerVictim->CanBlock())
2682 {
2683 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2684 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->Block)
2685 {
2686 chance = playerVictim->GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2687 skillBonus = 0.04f * skillDiff;
2688 }
2689 }
2690 }
2691 else
2692 {
2694 {
2695 chance = 5.0f;
2697
2698 if (skillDiff <= 10)
2699 skillBonus = skillDiff * 0.1f;
2700 else
2701 skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
2702 }
2703 }
2704
2705 chance += skillBonus;
2706 return std::max(chance, 0.0f);
2707}
2708
2710{
2711 float chance = 0.f;
2712 if (GetTypeId() == TYPEID_PLAYER)
2713 {
2714 switch (attackType)
2715 {
2716 case BASE_ATTACK:
2718 break;
2719 case OFF_ATTACK:
2721 break;
2722 case RANGED_ATTACK:
2724 break;
2725 // Just for good manner
2726 default:
2727 chance = 0.0f;
2728 break;
2729 }
2730 }
2731 else
2732 {
2733 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2734 {
2735 chance = 5.0f;
2738 }
2739 }
2740
2741 return chance;
2742}
2743
2744float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2745{
2746 int32 const attackerWeaponSkill = attacker->GetWeaponSkillValue(attackType, this);
2747 int32 const victimDefenseSkill = GetDefenseSkillValue(attacker);
2748 int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
2749
2750 float skillBonus = 0.0f;
2751 float chance = critDone;
2752
2753 // flat aura mods
2754 if (attackType == RANGED_ATTACK)
2756 else
2758
2759 // reduce crit chance from Rating for players
2760 if (attacker->CanApplyResilience())
2761 Unit::ApplyResilience(this, &chance, nullptr, false, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
2762
2763 // applied after resilience
2765
2766 // Apply crit chance from defense skill
2767 if (GetTypeId() == TYPEID_PLAYER)
2768 skillBonus = -skillDiff * 0.04f;
2769 else
2770 {
2771 skillBonus = -skillDiff * 0.12f;
2772 if (skillDiff >= 15)
2773 skillBonus -= 3.0f;
2774 }
2775
2776 chance += skillBonus;
2777 return std::max(chance, 0.f);
2778}
2779
2780float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2781{
2782 float chance = GetUnitCriticalChanceDone(attackType);
2783 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2784}
2785
2787{
2788 uint32 value = 0;
2789 if (Player const* player = ToPlayer())
2790 {
2791 Item* item = player->GetWeaponForAttack(attType, true);
2792
2793 // feral or unarmed skill only for base attack
2794 if (attType != BASE_ATTACK && !item)
2795 return 0;
2796
2797 if (IsInFeralForm())
2798 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
2799
2800 // weapon skill or (unarmed for base attack)
2801 uint32 skill = SKILL_UNARMED;
2802 if (item)
2803 skill = item->GetSkill();
2804
2805 // in PvP use full skill instead current skill value
2806 value = (target && target->IsControlledByPlayer())
2807 ? player->GetMaxSkillValue(skill)
2808 : player->GetSkillValue(skill);
2809 // Modify value from ratings
2810 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL));
2811 switch (attType)
2812 {
2813 case BASE_ATTACK:
2814 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));
2815 break;
2816 case OFF_ATTACK:
2817 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));
2818 break;
2819 case RANGED_ATTACK:
2820 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));
2821 break;
2822 default:
2823 break;
2824 }
2825 }
2826 else
2827 value = GetMaxSkillValueForLevel(target);
2828 return value;
2829}
2830
2832{
2833 while (!m_removedAuras.empty())
2834 {
2835 delete m_removedAuras.front();
2836 m_removedAuras.pop_front();
2837 }
2838
2840}
2841
2843{
2846
2847 // remove finished spells from current pointers
2848 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
2849 {
2850 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2851 {
2853 m_currentSpells[i] = nullptr; // remove pointer
2854 }
2855 }
2856
2857 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2859 {
2860 Aura* i_aura = m_auraUpdateIterator->second;
2861 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2862 i_aura->UpdateOwner(time, this);
2863 }
2864
2865 // remove expired auras - do that after updates(used in scripts?)
2866 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2867 {
2868 if (i->second->IsExpired())
2870 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2871 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2872 else
2873 ++i;
2874 }
2875
2876 for (VisibleAuraMap::iterator itr = m_visibleAuras.begin(); itr != m_visibleAuras.end(); ++itr)
2877 if (itr->second->IsNeedClientUpdate())
2878 itr->second->ClientUpdate();
2879
2881
2882 if (!m_gameObj.empty())
2883 {
2884 GameObjectList::iterator itr;
2885 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
2886 {
2887 if (!(*itr)->isSpawned())
2888 {
2889 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
2890 (*itr)->SetRespawnTime(0);
2891 (*itr)->Delete();
2892 m_gameObj.erase(itr++);
2893 }
2894 else
2895 ++itr;
2896 }
2897 }
2898
2900}
2901
2903{
2904 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
2905
2906 // check "realtime" interrupts
2907 if ((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->Id == 75))
2908 {
2909 // cancel wand shoot
2910 if (autoRepeatSpellInfo->Id != 75)
2912 m_AutoRepeatFirstCast = true;
2913 return;
2914 }
2915
2916 // apply delay (Auto Shot (spellID 75) not affected)
2917 if (m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 && autoRepeatSpellInfo->Id != 75)
2919 m_AutoRepeatFirstCast = false;
2920
2921 // castroutine
2923 {
2924 // Check if able to cast
2926 if (result != SPELL_CAST_OK)
2927 {
2928 if (autoRepeatSpellInfo->Id != 75)
2930 else if (GetTypeId() == TYPEID_PLAYER)
2931 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, 1, result);
2932
2933 return;
2934 }
2935
2936 // we want to shoot
2937 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_FULL_MASK);
2939
2940 // all went good, reset attack
2942 }
2943}
2944
2946{
2947 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2948
2949 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
2950
2951 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
2952 return;
2953
2954 // break same type spell if it is not delayed
2955 InterruptSpell(CSpellType, false);
2956
2957 // special breakage effects:
2958 switch (CSpellType)
2959 {
2961 {
2962 // generic spells always break channeled not delayed spells
2964
2965 // autorepeat breaking
2967 {
2968 // break autorepeat if not Auto Shot
2969 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
2971 m_AutoRepeatFirstCast = true;
2972 }
2973 if (pSpell->GetCastTime() > 0)
2975
2976 break;
2977 }
2979 {
2980 // channel spells always break generic non-delayed and any channeled spells
2983
2984 // it also does break autorepeat if not Auto Shot
2986 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
2989
2990 break;
2991 }
2993 {
2994 // only Auto Shoot does not break anything
2995 if (pSpell->GetSpellInfo()->Id != 75)
2996 {
2997 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3000 }
3001 // special action: set first cast flag
3002 m_AutoRepeatFirstCast = true;
3003
3004 break;
3005 }
3006 default:
3007 break; // other spell types don't break anything now
3008 }
3009
3010 // current spell (if it is still here) may be safely deleted now
3011 if (m_currentSpells[CSpellType])
3012 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3013
3014 // set new current spell
3015 m_currentSpells[CSpellType] = pSpell;
3016 pSpell->SetReferencedFromCurrent(true);
3017
3018 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3019}
3020
3021void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant, SpellCastResult result, Optional<SpellCastResult> resultOther /*= {}*/)
3022{
3023 //TC_LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
3024 Spell* spell = m_currentSpells[spellType];
3025 if (spell
3026 && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
3027 && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING))
3028 {
3029 // for example, do not let self-stun aura interrupt itself
3030 if (!spell->IsInterruptable())
3031 return;
3032
3033 // send autorepeat cancel message for autorepeat spells
3034 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3035 if (GetTypeId() == TYPEID_PLAYER)
3037
3038 if (spell->getState() != SPELL_STATE_FINISHED)
3039 spell->cancel(result, resultOther);
3040 else
3041 {
3042 m_currentSpells[spellType] = nullptr;
3043 spell->SetReferencedFromCurrent(false);
3044 }
3045
3046 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
3047 ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo());
3048 }
3049}
3050
3051void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/)
3052{
3053 Spell* spell = m_currentSpells[spellType];
3054 if (!spell)
3055 return;
3056
3057 if (spellType == CURRENT_CHANNELED_SPELL)
3058 spell->SendChannelUpdate(0);
3059
3060 spell->finish(ok);
3061}
3062
3063bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
3064{
3065 // We don't do loop here to explicitly show that melee spell is excluded.
3066 // Maybe later some special spells will be excluded too.
3067
3068 // generic spells are cast when they are not finished and not delayed
3071 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
3072 {
3073 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3074 {
3075 if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
3076 return true;
3077 }
3078 }
3079 // channeled spells may be delayed, but they are still considered cast
3080 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3082 {
3083 if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
3084 return true;
3085 }
3086 // autorepeat spells may be finished or delayed, but they are still considered cast
3087 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3088 return true;
3089
3090 return false;
3091}
3092
3093void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3094{
3095 // generic spells are interrupted if they are not finished or delayed
3096 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3097 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3098
3099 // autorepeat spells are interrupted if they are not finished or delayed
3100 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3101 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3102
3103 // channeled spells are interrupted if they are not finished, even if they are delayed
3104 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3106}
3107
3109{
3110 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3111 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
3112 return m_currentSpells[i];
3113 return nullptr;
3114}
3115
3117{
3118 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3119 return spell->GetCastTime();
3120 return 0;
3121}
3122
3124{
3125 // can always move when not casting
3127 return false;
3128
3130 if (spell->getState() == SPELL_STATE_FINISHED ||
3131 !(spell->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
3132 return false;
3133
3134 // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
3136 if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
3137 if (spell->GetSpellInfo()->IsMoveAllowedChannel())
3138 return false;
3139
3140 // prohibit movement for all other spell casts
3141 return true;
3142}
3143
3144bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3145{
3146 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3147}
3148
3149bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3150{
3151 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3152}
3153
3155{
3156 if (IsInWater())
3157 return c->CanEnterWater();
3158 else
3159 return c->CanWalk() || c->CanFly();
3160}
3161
3166
3168{
3170}
3171
3178
3179void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus /*oldLiquidStatus*/, Optional<LiquidData> const& newLiquidData)
3180{
3181 if (!IsControlledByPlayer())
3182 return;
3183
3184 // remove appropriate auras if we are swimming/not swimming respectively
3185 if (IsInWater())
3187 else
3189
3190 // liquid aura handling
3191 LiquidTypeEntry const* curLiquid = nullptr;
3192 if (IsInWater() && newLiquidData)
3193 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3194 if (curLiquid != _lastLiquid)
3195 {
3199
3200 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3201 _lastLiquid = curLiquid;
3202
3203 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3204 CastSpell(this, curLiquid->SpellID, true);
3205 }
3206}
3207
3212
3214{
3215 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3216
3217 // Check if these can stack anyway
3218 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3219 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3220
3221 // world gameobjects can't own auras and they send empty casterguid
3222 // checked on sniffs with spell 22247
3223 if (createInfo.CasterGUID.IsGameObject())
3224 {
3225 createInfo.Caster = nullptr;
3226 createInfo.CasterGUID.Clear();
3227 }
3228
3229 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3230 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3231 {
3232 // check if cast item changed
3233 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3234
3235 // find current aura from spell and change it's stackamount, or refresh it's duration
3237 {
3238 // effect masks do not match
3239 // extremely rare case
3240 // let's just recreate aura
3241 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3242 return nullptr;
3243
3244 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3245 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3246 {
3247 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3248 if (!auraEff)
3249 continue;
3250
3251 int32 bp = spellEffectInfo.BasePoints;
3252 if (createInfo.BaseAmount)
3253 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3254
3255 int32* oldBP = const_cast<int32*>(&(auraEff->m_baseAmount));
3256 *oldBP = bp;
3257 }
3258
3259 // correct cast item guid if needed
3260 if (castItemGUID != foundAura->GetCastItemGUID())
3261 {
3262 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3263 *oldGUID = castItemGUID;
3264 }
3265
3266 // try to increase stack amount
3267 foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3268 return foundAura;
3269 }
3270 }
3271
3272 return nullptr;
3273}
3274
3275void Unit::_AddAura(UnitAura* aura, Unit* caster)
3276{
3278 m_ownedAuras.emplace(aura->GetId(), aura);
3279
3280 _RemoveNoStackAurasDueToAura(aura, true);
3281
3282 if (aura->IsRemoved())
3283 return;
3284
3285 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3286 if (aura->IsSingleTarget())
3287 {
3289 /* @HACK: Player is not in world during loading auras.
3290 * Single target auras are not saved or loaded from database
3291 * but may be created as a result of aura links.
3292 */
3293
3294 // register single target aura
3295 caster->GetSingleCastAuras().push_back(aura);
3296 // remove other single target auras
3297 Unit::AuraList& scAuras = caster->GetSingleCastAuras();
3298 for (Unit::AuraList::iterator itr = scAuras.begin(); itr != scAuras.end();)
3299 {
3300 if ((*itr) != aura &&
3301 (*itr)->IsSingleTargetWith(aura))
3302 {
3303 (*itr)->Remove();
3304 itr = scAuras.begin();
3305 }
3306 else
3307 ++itr;
3308 }
3309 }
3310}
3311
3312// creates aura application instance and registers it in lists
3313// aura application effects are handled separately to prevent aura list corruption
3315{
3316 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3318
3319 // just return if the aura has been already removed
3320 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3321 if (aura->IsRemoved())
3322 {
3323 TC_LOG_ERROR("spells", "Unit::_CreateAuraApplication() called with a removed aura. Check if OnEffectHitTarget() is triggering any spell with apply aura effect (that's not allowed!)\nUnit: {}\nAura: {}", GetDebugInfo(), aura->GetDebugInfo());
3324 return nullptr;
3325 }
3326
3327 // aura mustn't be already applied on target
3328 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3329
3330 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3331 uint32 aurId = aurSpellInfo->Id;
3332
3333 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3334 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3335 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3336 return nullptr;
3337
3338 Unit* caster = aura->GetCaster();
3339
3340 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3341 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3342
3343 if (aurSpellInfo->AuraInterruptFlags)
3344 {
3345 m_interruptableAuras.push_back(aurApp);
3346 AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
3347 }
3348
3349 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3350 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3351
3352 aura->_ApplyForTarget(this, caster, aurApp);
3353 return aurApp;
3354}
3355
3356void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3357{
3358 ASSERT(aura);
3359 ASSERT(aura->HasEffect(effIndex));
3361 ASSERT(aurApp);
3362 if (!aurApp->GetEffectMask())
3363 _ApplyAura(aurApp, 1 << effIndex);
3364 else
3365 aurApp->_HandleEffect(effIndex, true);
3366}
3367
3368// handles effects of aura application
3369// should be done after registering aura in lists
3371{
3372 Aura* aura = aurApp->GetBase();
3373
3374 _RemoveNoStackAurasDueToAura(aura, false);
3375
3376 if (aurApp->GetRemoveMode())
3377 return;
3378
3379 // Update target aura state flag
3380 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3381 {
3382 uint32 aStateMask = (1 << (aState - 1));
3383 // force update so the new caster registers it
3384 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && HasFlag(UNIT_FIELD_AURASTATE, aStateMask))
3386 else
3387 ModifyAuraState(aState, true);
3388 }
3389
3390 if (aurApp->GetRemoveMode())
3391 return;
3392
3393 // Sitdown on apply aura req seated
3396
3397 Unit* caster = aura->GetCaster();
3398
3399 if (aurApp->GetRemoveMode())
3400 return;
3401
3402 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3403
3404 // apply effects of the aura
3405 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3406 {
3407 if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
3408 aurApp->_HandleEffect(i, true);
3409 }
3410
3411 if (Player* player = ToPlayer())
3412 {
3413 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aura->GetId()))
3414 player->UpdateVisibleGameobjectsOrSpellClicks();
3415
3416 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_AURA, aura->GetId(), 0, aura->GetCaster());
3417 }
3418}
3419
3420// removes aura application from lists and unapplies effects
3421void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3422{
3423 AuraApplication * aurApp = i->second;
3424 ASSERT(aurApp);
3425 ASSERT(!aurApp->GetRemoveMode());
3426 ASSERT(aurApp->GetTarget() == this);
3427
3428 aurApp->SetRemoveMode(removeMode);
3429 Aura* aura = aurApp->GetBase();
3430 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3431
3432 // dead loop is killing the server probably
3433 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3434
3436
3437 Unit* caster = aura->GetCaster();
3438
3439 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3440 m_appliedAuras.erase(i);
3441
3442 if (aura->GetSpellInfo()->AuraInterruptFlags)
3443 {
3444 m_interruptableAuras.remove(aurApp);
3446 }
3447
3448 bool auraStateFound = false;
3449 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3450 if (auraState)
3451 {
3452 bool canBreak = false;
3453 // Get mask of all aurastates from remaining auras
3454 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3455 {
3456 if (itr->second == aurApp)
3457 {
3458 m_auraStateAuras.erase(itr);
3459 itr = m_auraStateAuras.lower_bound(auraState);
3460 canBreak = true;
3461 continue;
3462 }
3463 auraStateFound = true;
3464 ++itr;
3465 }
3466 }
3467
3468 aurApp->_Remove();
3469 aura->_UnapplyForTarget(this, caster, aurApp);
3470
3471 // remove effects of the spell - needs to be done after removing aura from lists
3472 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3473 {
3474 if (aurApp->HasEffect(itr))
3475 aurApp->_HandleEffect(itr, false);
3476 }
3477
3478 // all effect mustn't be applied
3479 ASSERT(!aurApp->GetEffectMask());
3480
3481 // Remove totem at next update if totem loses its aura
3482 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3483 {
3484 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3486 }
3487
3488 // Remove aurastates only if needed and were not found
3489 if (auraState)
3490 {
3491 if (!auraStateFound)
3492 ModifyAuraState(auraState, false);
3493 else
3494 {
3495 // update for casters, some shouldn't 'see' the aura state
3496 uint32 aStateMask = (1 << (auraState - 1));
3497 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3499 }
3500 }
3501
3502 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3503
3504 if (Player* player = ToPlayer())
3505 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3506 player->UpdateVisibleGameobjectsOrSpellClicks();
3507
3508 i = m_appliedAuras.begin();
3509}
3510
3512{
3513 // aura can be removed from unit only if it's applied on it, shouldn't happen
3514 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3515
3516 uint32 spellId = aurApp->GetBase()->GetId();
3517 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3518
3519 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3520 {
3521 if (iter->second == aurApp)
3522 {
3523 _UnapplyAura(iter, removeMode);
3524 return;
3525 }
3526 else
3527 ++iter;
3528 }
3529 ABORT();
3530}
3531
3533{
3534 SpellInfo const* spellProto = aura->GetSpellInfo();
3535
3536 // passive spell special case (only non stackable with ranks)
3537 if (spellProto->IsPassiveStackableWithRanks())
3538 return;
3539
3540 if (!IsHighestExclusiveAura(aura))
3541 {
3542 aura->Remove();
3543 return;
3544 }
3545
3546 if (owned)
3547 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3548 else
3549 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3550}
3551
3552void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
3553{
3554 if (apply)
3555 m_modAuras[aurEff->GetAuraType()].push_back(aurEff);
3556 else
3557 m_modAuras[aurEff->GetAuraType()].remove(aurEff);
3558}
3559
3560// All aura base removes should go through this function!
3561void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3562{
3563 Aura* aura = i->second;
3564 ASSERT(!aura->IsRemoved());
3565
3566 // if unit currently update aura list then make safe update iterator shift to next
3567 if (m_auraUpdateIterator == i)
3569
3570 m_ownedAuras.erase(i);
3571 m_removedAuras.push_back(aura);
3572
3573 // Unregister single target aura
3574 if (aura->IsSingleTarget())
3575 aura->UnregisterSingleTarget();
3576
3577 aura->_Remove(removeMode);
3578
3579 i = m_ownedAuras.begin();
3580}
3581
3582void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
3583{
3584 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3585 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3586 {
3587 RemoveOwnedAura(itr, removeMode);
3588 itr = m_ownedAuras.lower_bound(spellId);
3589 }
3590 else
3591 ++itr;
3592}
3593
3595{
3596 if (aura->IsRemoved())
3597 return;
3598
3599 ASSERT(aura->GetOwner() == this);
3600
3601 if (removeMode == AURA_REMOVE_NONE)
3602 {
3603 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3604 return;
3605 }
3606
3607 uint32 spellId = aura->GetId();
3608 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3609
3610 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3611 {
3612 if (itr->second == aura)
3613 {
3614 RemoveOwnedAura(itr, removeMode);
3615 return;
3616 }
3617 }
3618
3619 ABORT();
3620}
3621
3622Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, Aura* except) const
3623{
3624 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3625 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3626 {
3627 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3628 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3629 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3630 && (!except || except != itr->second))
3631 {
3632 return itr->second;
3633 }
3634 }
3635 return nullptr;
3636}
3637
3638void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3639{
3640 AuraApplication * aurApp = i->second;
3641 // Do not remove aura which is already being removed
3642 if (aurApp->GetRemoveMode())
3643 return;
3644 Aura* aura = aurApp->GetBase();
3645 _UnapplyAura(i, mode);
3646 // Remove aura - for Area and Target auras
3647 if (aura->GetOwner() == this)
3648 aura->Remove(mode);
3649}
3650
3651void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint8 reqEffMask, AuraRemoveMode removeMode)
3652{
3653 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3654 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3655 {
3656 Aura const* aura = iter->second->GetBase();
3657 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3658 && (!caster || aura->GetCasterGUID() == caster))
3659 {
3660 RemoveAura(iter, removeMode);
3661 return;
3662 }
3663 else
3664 ++iter;
3665 }
3666}
3667
3669{
3670 // we've special situation here, RemoveAura called while during aura removal
3671 // this kind of call is needed only when aura effect removal handler
3672 // or event triggered by it expects to remove
3673 // not yet removed effects of an aura
3674 if (aurApp->GetRemoveMode())
3675 {
3676 // remove remaining effects of an aura
3677 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3678 {
3679 if (aurApp->HasEffect(itr))
3680 aurApp->_HandleEffect(itr, false);
3681 }
3682 return;
3683 }
3684 // no need to remove
3685 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3686 return;
3687
3688 uint32 spellId = aurApp->GetBase()->GetId();
3689 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3690
3691 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3692 {
3693 if (aurApp == iter->second)
3694 {
3695 RemoveAura(iter, mode);
3696 return;
3697 }
3698 else
3699 ++iter;
3700 }
3701}
3702
3704{
3705 if (aura->IsRemoved())
3706 return;
3707 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3708 RemoveAura(aurApp, mode);
3709}
3710
3711void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3712{
3713 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3714 {
3715 if (check(iter->second))
3716 {
3717 RemoveAura(iter, removeMode);
3718 continue;
3719 }
3720 ++iter;
3721 }
3722}
3723
3724void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3725{
3726 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3727 {
3728 if (check(iter->second))
3729 {
3730 RemoveOwnedAura(iter, removeMode);
3731 continue;
3732 }
3733 ++iter;
3734 }
3735}
3736
3737void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3738{
3739 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3740 {
3741 if (check(iter->second))
3742 {
3743 RemoveAura(iter, removeMode);
3744 iter = m_appliedAuras.lower_bound(spellId);
3745 continue;
3746 }
3747 ++iter;
3748 }
3749}
3750
3751void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3752{
3753 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3754 {
3755 if (check(iter->second))
3756 {
3757 RemoveOwnedAura(iter, removeMode);
3758 iter = m_ownedAuras.lower_bound(spellId);
3759 continue;
3760 }
3761 ++iter;
3762 }
3763}
3764
3765void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3766{
3767 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3768 {
3769 Aura* aura = (*iter)->GetBase();
3771 ASSERT(aurApp);
3772
3773 ++iter;
3774 if (check(aurApp))
3775 {
3776 uint32 removedAuras = m_removedAurasCount;
3777 RemoveAura(aurApp, removeMode);
3778 if (m_removedAurasCount > removedAuras + 1)
3779 iter = m_modAuras[auraType].begin();
3780 }
3781 }
3782}
3783
3784void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
3785{
3786 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3787 {
3788 Aura const* aura = iter->second->GetBase();
3789 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3790 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3791 {
3792 RemoveAura(iter, removeMode);
3793 iter = m_appliedAuras.lower_bound(spellId);
3794 }
3795 else
3796 ++iter;
3797 }
3798}
3799
3800void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode)
3801{
3802 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3803 for (AuraMap::iterator iter = range.first; iter != range.second;)
3804 {
3805 Aura* aura = iter->second;
3806 if ((aura->GetType() == UNIT_AURA_TYPE)
3807 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3808 {
3809 aura->ModStackAmount(-1, removeMode);
3810 return;
3811 }
3812 else
3813 ++iter;
3814 }
3815}
3816
3817void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
3818{
3819 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3820 for (AuraMap::iterator iter = range.first; iter != range.second;)
3821 {
3822 Aura* aura = iter->second;
3823 if (aura->GetCasterGUID() == casterGUID)
3824 {
3825 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
3826
3827 // Call OnDispel hook on AuraScript
3828 aura->CallScriptDispel(&dispelInfo);
3829
3832 else
3834
3835 // Call AfterDispel hook on AuraScript
3836 aura->CallScriptAfterDispel(&dispelInfo);
3837
3838 return;
3839 }
3840 else
3841 ++iter;
3842 }
3843}
3844
3846{
3847 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3848 for (AuraMap::iterator iter = range.first; iter != range.second;)
3849 {
3850 Aura* aura = iter->second;
3851 if (aura->GetCasterGUID() == casterGUID)
3852 {
3853 int32 damage[MAX_SPELL_EFFECTS];
3854 int32 baseDamage[MAX_SPELL_EFFECTS];
3855 uint8 effMask = 0;
3856 uint8 recalculateMask = 0;
3857 Unit* caster = aura->GetCaster();
3858 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3859 {
3860 if (aura->GetEffect(i))
3861 {
3862 baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
3863 damage[i] = aura->GetEffect(i)->GetAmount();
3864 effMask |= (1<<i);
3865 if (aura->GetEffect(i)->CanBeRecalculated())
3866 recalculateMask |= (1<<i);
3867 }
3868 else
3869 {
3870 baseDamage[i] = 0;
3871 damage[i] = 0;
3872 }
3873 }
3874
3875 bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
3876 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
3877 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
3878
3879 if (Unit* unitStealer = stealer->ToUnit())
3880 {
3881 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
3882 {
3883 if (stealCharge)
3884 oldAura->ModCharges(1);
3885 else
3886 oldAura->ModStackAmount(1);
3887 oldAura->SetDuration(int32(dur));
3888 }
3889 else
3890 {
3891 // single target state must be removed before aura creation to preserve existing single target aura
3892 if (aura->IsSingleTarget())
3893 aura->UnregisterSingleTarget();
3894
3895 AuraCreateInfo createInfo(aura->GetSpellInfo(), effMask, unitStealer);
3896 createInfo
3898 .SetBaseAmount(baseDamage);
3899
3900 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
3901 {
3902 // created aura must not be single target aura,, so stealer won't loose it on recast
3903 if (newAura->IsSingleTarget())
3904 {
3905 newAura->UnregisterSingleTarget();
3906 // bring back single target aura status to the old aura
3907 aura->SetIsSingleTarget(true);
3908 caster->GetSingleCastAuras().push_back(aura);
3909 }
3910 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
3911 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]);
3912 newAura->ApplyForTargets();
3913 }
3914 }
3915 }
3916
3917 if (stealCharge)
3919 else
3921
3922 return;
3923 }
3924 else
3925 ++iter;
3926 }
3927}
3928
3930{
3931 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3932 {
3933 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
3934 {
3935 RemoveAura(iter);
3936 iter = m_appliedAuras.lower_bound(spellId);
3937 }
3938 else
3939 ++iter;
3940 }
3941}
3942
3943void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
3944{
3945 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3946 {
3947 Aura* aura = (*iter)->GetBase();
3949 ASSERT(aurApp);
3950
3951 ++iter;
3952 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
3953 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
3954 {
3955 uint32 removedAuras = m_removedAurasCount;
3956 RemoveAura(aurApp);
3957 if (m_removedAurasCount > removedAuras + 1)
3958 iter = m_modAuras[auraType].begin();
3959 }
3960 }
3961}
3962
3964{
3965 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3966 {
3967 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
3968 if (spell->Attributes & flags)
3969 RemoveAura(iter);
3970 else
3971 ++iter;
3972 }
3973}
3974
3976{
3977 // single target auras from other casters
3978 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
3979 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
3980 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
3981 // leading to assertion failures if the aura was cast on a player that can
3982 // (and is changing map at the point where this function is called).
3983 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
3984 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
3985 // to register in m_appliedAuras
3986 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3987 {
3988 Aura const* aura = iter->second;
3989
3990 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
3991 {
3992 if (!newPhase)
3993 RemoveOwnedAura(iter);
3994 else
3995 {
3996 Unit* caster = aura->GetCaster();
3997 if (!caster || !caster->InSamePhase(newPhase))
3998 RemoveOwnedAura(iter);
3999 else
4000 ++iter;
4001 }
4002 }
4003 else
4004 ++iter;
4005 }
4006
4007 // single target auras at other targets
4008 AuraList& scAuras = GetSingleCastAuras();
4009 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4010 {
4011 Aura* aura = *iter;
4012 if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase))
4013 {
4014 aura->Remove();
4015 iter = scAuras.begin();
4016 }
4017 else
4018 ++iter;
4019 }
4020}
4021
4023{
4024 if (!(m_interruptMask & flag))
4025 return;
4026
4027 // interrupt auras
4028 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4029 {
4030 Aura* aura = (*iter)->GetBase();
4031 ++iter;
4032 if ((aura->GetSpellInfo()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except))
4033 {
4034 uint32 removedAuras = m_removedAurasCount;
4035 RemoveAura(aura);
4036 if (m_removedAurasCount > removedAuras + 1)
4037 iter = m_interruptableAuras.begin();
4038 }
4039 }
4040
4041 // interrupt channeled spell
4043 if (spell->getState() == SPELL_STATE_CASTING
4044 && (spell->m_spellInfo->ChannelInterruptFlags & flag)
4045 && spell->m_spellInfo->Id != except)
4047
4049}
4050
4051void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag96 const& familyFlag, ObjectGuid casterGUID)
4052{
4053 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4054 {
4055 Aura const* aura = iter->second->GetBase();
4056 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4057 {
4058 SpellInfo const* spell = aura->GetSpellInfo();
4059 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4060 {
4061 RemoveAura(iter);
4062 continue;
4063 }
4064 }
4065 ++iter;
4066 }
4067}
4068
4070{
4071 if (withRoot)
4073
4075}
4076
4077void Unit::RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4078{
4079 std::vector<Aura*> aurasToUpdateTargets;
4080 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4081 {
4082 Aura* aura = aurApp->GetBase();
4083 if (exceptSpellId && aura->GetId() == exceptSpellId)
4084 return false;
4085
4086 uint32 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4087 if (!(appliedMechanicMask & mechanicMaskToRemove))
4088 return false;
4089
4090 // spell mechanic matches required mask for removal
4091 if ((1 << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4092 return true;
4093
4094 // effect mechanic matches required mask for removal - don't remove, only update targets
4095 aurasToUpdateTargets.push_back(aura);
4096 return false;
4097 }, removeMode);
4098
4099 for (Aura* aura : aurasToUpdateTargets)
4100 {
4101 aura->UpdateTargetMap(aura->GetCaster());
4102
4103 // Fully remove the aura if all effects were removed
4104 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4105 aura->Remove(removeMode);
4106 }
4107}
4108
4110{
4111 uint32 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4112 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4113 {
4114 Aura const* aura = iter->second->GetBase();
4115 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4116 {
4117 RemoveAura(iter);
4118 continue;
4119 }
4120 ++iter;
4121 }
4122}
4123
4125{
4126 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4127 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4128 {
4129 Aura* aura = iter->second;
4130 ++iter;
4131 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4132 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4133 {
4134 AuraApplication * aurApp = itr->second;
4135 ++itr;
4136 Unit* target = aurApp->GetTarget();
4137 if (target == this)
4138 continue;
4139 target->RemoveAura(aurApp);
4140 // things linked on aura remove may apply new area aura - so start from the beginning
4141 iter = m_ownedAuras.begin();
4142 }
4143 }
4144
4145 // remove area auras owned by others
4146 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4147 {
4148 if (iter->second->GetBase()->GetOwner() != this)
4149 {
4150 RemoveAura(iter);
4151 }
4152 else
4153 ++iter;
4154 }
4155}
4156
4158{
4159 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4160 // we want to have all auras removed, so use your brain when linking events
4161 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4162 {
4163 AuraApplicationMap::iterator aurAppIter;
4164 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4166
4167 AuraMap::iterator aurIter;
4168 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4169 RemoveOwnedAura(aurIter);
4170
4171 const int maxIteration = 50;
4172 // give this loop a few tries, if there are still auras then log as much information as possible
4173 if (counter >= maxIteration)
4174 {
4175 std::stringstream sstr;
4176 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4177 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4178 sstr << GetDebugInfo() << "\n";
4179
4180 if (!m_appliedAuras.empty())
4181 {
4182 sstr << "m_appliedAuras:" << "\n";
4183
4184 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4185 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4186 }
4187
4188 if (!m_ownedAuras.empty())
4189 {
4190 sstr << "m_ownedAuras:" << "\n";
4191
4192 for (auto const& [spellId, aura] : m_ownedAuras)
4193 sstr << aura->GetDebugInfo() << "\n";
4194 }
4195
4196 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4197 ABORT_MSG("%s", sstr.str().c_str());
4198
4199 break;
4200 }
4201 }
4202}
4203
4205{
4206 // in join, remove positive buffs, on end, remove negative
4207 // used to remove positive visible auras in arenas
4208 RemoveAppliedAuras([](AuraApplication const* aurApp)
4209 {
4210 Aura const* aura = aurApp->GetBase();
4211 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_DONT_REMOVE_IN_ARENA) // don't remove stances, shadowform, pally/hunter auras
4212 && !aura->IsPassive() // don't remove passive auras
4213 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT))) || // not negative death persistent auras
4214 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ON_ARENA_ENTER); // special marker, always remove
4215 });
4216}
4217
4219{
4220 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4221 return;
4222
4223 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4224 // don't remove clone caster on evade (to be verified)
4226}
4227
4229{
4230 // used just after dieing to remove all visible auras
4231 // and disable the mods for the passive ones
4232 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4233 {
4234 Aura const* aura = iter->second->GetBase();
4235 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4237 else
4238 ++iter;
4239 }
4240
4241 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4242 {
4243 Aura* aura = iter->second;
4244 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4246 else
4247 ++iter;
4248 }
4249}
4250
4252{
4253 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4254 {
4255 Aura const* aura = iter->second->GetBase();
4256 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4258 else
4259 ++iter;
4260 }
4261
4262 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4263 {
4264 Aura* aura = iter->second;
4265 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4267 else
4268 ++iter;
4269 }
4270}
4271
4273{
4274 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4275 {
4276 Aura const* aura = iter->second->GetBase();
4277 if (aura->GetSpellInfo()->HasAura(type))
4278 ++iter;
4279 else
4281 }
4282
4283 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4284 {
4285 Aura* aura = iter->second;
4286 if (aura->GetSpellInfo()->HasAura(type))
4287 ++iter;
4288 else
4290 }
4291}
4292
4294{
4295 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4296 {
4297 Aura const* aura = iter->second->GetBase();
4298 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4299 ++iter;
4300 else
4302 }
4303
4304 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4305 {
4306 Aura* aura = iter->second;
4307 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4308 ++iter;
4309 else
4311 }
4312}
4313
4315{
4316 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4317 {
4318 Aura* aura = iter->second;
4319 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4320 {
4321 RemoveOwnedAura(iter);
4322 continue;
4323 }
4324 ++iter;
4325 }
4326}
4327
4328void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4329{
4330 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4331 for (; range.first != range.second; ++range.first)
4332 {
4333 Aura* aura = range.first->second;
4334 if (!caster || aura->GetCasterGUID() == caster)
4335 {
4336 if (aura->GetDuration() < delaytime)
4337 aura->SetDuration(0);
4338 else
4339 aura->SetDuration(aura->GetDuration() - delaytime);
4340
4341 // update for out of range group members (on 1 slot use)
4343 }
4344 }
4345}
4346
4348{
4349 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4350 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4351}
4352
4354{
4355 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4356 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4357}
4358
4359AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4360{
4361 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4362 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4363 {
4364 if (itr->second->HasEffect(effIndex)
4365 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4366 {
4367 return itr->second->GetBase()->GetEffect(effIndex);
4368 }
4369 }
4370 return nullptr;
4371}
4372
4374{
4375 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4376 while (rankSpell)
4377 {
4378 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4379 return aurEff;
4380 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4381 }
4382 return nullptr;
4383}
4384
4386{
4387 AuraEffectList const& auras = GetAuraEffectsByType(type);
4388 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
4389 {
4390 if (effIndex != (*itr)->GetEffIndex())
4391 continue;
4392 SpellInfo const* spell = (*itr)->GetSpellInfo();
4393 if (spell->SpellIconID == iconId && spell->SpellFamilyName == uint32(name) && !spell->SpellFamilyFlags)
4394 return *itr;
4395 }
4396 return nullptr;
4397}
4398
4399AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID) const
4400{
4401 AuraEffectList const& auras = GetAuraEffectsByType(type);
4402 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4403 {
4404 SpellInfo const* spell = (*i)->GetSpellInfo();
4405 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & flag96(familyFlag1, familyFlag2, familyFlag3))
4406 {
4407 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4408 continue;
4409 return (*i);
4410 }
4411 }
4412 return nullptr;
4413}
4414
4416{
4417 return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex);
4418}
4419
4420AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication * except) const
4421{
4422 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4423 for (; range.first != range.second; ++range.first)
4424 {
4425 AuraApplication* app = range.first->second;
4426 Aura const* aura = app->GetBase();
4427
4428 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4429 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4430 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4431 && (!except || except != app))
4432 {
4433 return app;
4434 }
4435 }
4436 return nullptr;
4437}
4438
4439Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4440{
4441 AuraApplication * aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4442 return aurApp ? aurApp->GetBase() : nullptr;
4443}
4444
4445AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
4446{
4447 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4448 while (rankSpell)
4449 {
4450 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4451 return aurApp;
4452 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4453 }
4454 return nullptr;
4455}
4456
4457Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4458{
4459 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4460 return aurApp ? aurApp->GetBase() : nullptr;
4461}
4462
4463void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4464{
4465 // we should not be able to dispel diseases if the target is affected by unholy blight
4466 if (dispelMask & (1 << DISPEL_DISEASE) && HasAura(50536))
4467 dispelMask &= ~(1 << DISPEL_DISEASE);
4468
4469 AuraMap const& auras = GetOwnedAuras();
4470 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4471 {
4472 Aura* aura = itr->second;
4473 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4474 if (!aurApp)
4475 continue;
4476
4477 // don't try to remove passive auras
4478 if (aura->IsPassive())
4479 continue;
4480
4481 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4482 {
4483 // do not remove positive auras if friendly target
4484 // negative auras if non-friendly
4485 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4486 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4487 continue;
4488
4489 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4490 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4491 if (!chance)
4492 continue;
4493
4494 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4495 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4496 // Polymorph instead of 1 / (5 + 1) -> 16%.
4497 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
4498 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4499 if (charges > 0)
4500 dispelList.emplace_back(aura, chance, charges);
4501 }
4502 }
4503}
4504
4505bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4506{
4507 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4508 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4509 {
4510 if (itr->second->HasEffect(effIndex)
4511 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4512 {
4513 return true;
4514 }
4515 }
4516 return false;
4517}
4518
4520{
4521 uint32 count = 0;
4522 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4523
4524 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4525 {
4526 if (itr->second->GetBase()->GetStackAmount() == 0)
4527 ++count;
4528 else
4529 count += (uint32)itr->second->GetBase()->GetStackAmount();
4530 }
4531
4532 return count;
4533}
4534
4535bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4536{
4537 if (GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask))
4538 return true;
4539 return false;
4540}
4541
4542bool Unit::HasAuraType(AuraType auraType) const
4543{
4544 return (!m_modAuras[auraType].empty());
4545}
4546
4548{
4549 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4550 if (caster == eff->GetCasterGUID())
4551 return true;
4552 return false;
4553}
4554
4555bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4556{
4557 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4558 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4559 if (miscvalue == (*i)->GetMiscValue())
4560 return true;
4561 return false;
4562}
4563
4564bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4565{
4566 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4567 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4568 if ((*i)->IsAffectingSpell(affectedSpell))
4569 return true;
4570 return false;
4571}
4572
4573bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4574{
4575 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4576 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4577 if (value == (*i)->GetAmount())
4578 return true;
4579 return false;
4580}
4581
4582bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4583{
4584 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4585 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4586 return true;
4587 return false;
4588}
4589
4591{
4592 if (!(m_interruptMask & flag))
4593 return false;
4594 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4595 {
4596 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->AuraInterruptFlags & flag && (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4597 return true;
4598 }
4599 return false;
4600}
4601
4602bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const
4603{
4604 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4605 {
4606 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4607 if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
4608 return true;
4609
4610 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4611 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4612 if (mechanicMask & (1 << spellEffectInfo.Mechanic))
4613 return true;
4614 }
4615
4616 return false;
4617}
4618
4619bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster, bool triggered) const
4620{
4621 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
4622 DiminishingLevels level = GetDiminishing(diminishGroup);
4623 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4624 {
4625 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4626 if (spellInfo->GetDiminishingReturnsGroupForSpell(triggered) != diminishGroup)
4627 continue;
4628
4629 int32 existingDuration = itr->second->GetBase()->GetDuration();
4630 int32 newDuration = auraSpellInfo->GetMaxDuration();
4631 ApplyDiminishingToDuration(auraSpellInfo, triggered, newDuration, caster, level);
4632 if (newDuration > 0 && newDuration < existingDuration)
4633 return true;
4634 }
4635
4636 return false;
4637}
4638
4640{
4642 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4643 {
4644 if ((*i)->GetMiscValue() == script)
4645 if ((*i)->IsAffectingSpell(spell))
4646 return (*i);
4647 }
4648 return nullptr;
4649}
4650
4652{
4653 static const AuraType diseaseAuraTypes[] =
4654 {
4655 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4656 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4657 };
4658
4659 uint32 diseases = 0;
4660 for (AuraType aType : diseaseAuraTypes)
4661 {
4662 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4663 {
4664 // Get auras with disease dispel type by caster
4665 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4666 && (*itr)->GetCasterGUID() == casterGUID)
4667 {
4668 ++diseases;
4669
4670 if (remove)
4671 {
4672 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4673 itr = m_modAuras[aType].begin();
4674 continue;
4675 }
4676 }
4677 ++itr;
4678 }
4679 }
4680 return diseases;
4681}
4682
4684{
4685 static const AuraType diseaseAuraTypes[] =
4686 {
4690 };
4691
4692 uint32 dots = 0;
4693 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4694 {
4695 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4696 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4697 {
4698 // Get auras by caster
4699 if ((*i)->GetCasterGUID() == casterGUID)
4700 ++dots;
4701 }
4702 }
4703 return dots;
4704}
4705
4706int32 Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4707{
4708 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4709 if (mTotalAuraList.empty())
4710 return 0;
4711
4712 std::map<SpellGroup, int32> sameEffectSpellGroup;
4713 int32 modifier = 0;
4714
4715 for (AuraEffect const* aurEff : mTotalAuraList)
4716 {
4717 if (predicate(aurEff))
4718 {
4719 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4720 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4721 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4722 modifier += aurEff->GetAmount();
4723 }
4724 }
4725
4726 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
4727 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4728 modifier += itr->second;
4729
4730 return modifier;
4731}
4732
4733float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4734{
4735 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4736 if (mTotalAuraList.empty())
4737 return 1.0f;
4738
4739 std::map<SpellGroup, int32> sameEffectSpellGroup;
4740 float multiplier = 1.0f;
4741
4742 for (AuraEffect const* aurEff : mTotalAuraList)
4743 {
4744 if (predicate(aurEff))
4745 {
4746 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4747 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4748 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4749 AddPct(multiplier, aurEff->GetAmount());
4750 }
4751 }
4752
4753 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
4754 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4755 AddPct(multiplier, itr->second);
4756
4757 return multiplier;
4758}
4759
4760int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4761{
4762 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4763 if (mTotalAuraList.empty())
4764 return 0;
4765
4766 int32 modifier = 0;
4767 for (AuraEffect const* aurEff : mTotalAuraList)
4768 {
4769 if (predicate(aurEff))
4770 modifier = std::max(modifier, aurEff->GetAmount());
4771 }
4772
4773 return modifier;
4774}
4775
4776int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4777{
4778 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4779 if (mTotalAuraList.empty())
4780 return 0;
4781
4782 int32 modifier = 0;
4783 for (AuraEffect const* aurEff : mTotalAuraList)
4784 {
4785 if (predicate(aurEff))
4786 modifier = std::min(modifier, aurEff->GetAmount());
4787 }
4788
4789 return modifier;
4790}
4791
4793{
4794 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4795}
4796
4798{
4799 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4800}
4801
4803{
4804 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4805}
4806
4808{
4809 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4810}
4811
4813{
4814 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4815 {
4816 if ((aurEff->GetMiscValue() & miscMask) != 0)
4817 return true;
4818 return false;
4819 });
4820}
4821
4823{
4824 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4825 {
4826 if ((aurEff->GetMiscValue() & miscMask) != 0)
4827 return true;
4828 return false;
4829 });
4830}
4831
4832int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
4833{
4834 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
4835 {
4836 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
4837 return true;
4838 return false;
4839 });
4840}
4841
4843{
4844 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4845 {
4846 if ((aurEff->GetMiscValue() & miscMask) != 0)
4847 return true;
4848 return false;
4849 });
4850}
4851
4853{
4854 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4855 {
4856 if (aurEff->GetMiscValue() == miscValue)
4857 return true;
4858 return false;
4859 });
4860}
4861
4863{
4864 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4865 {
4866 if (aurEff->GetMiscValue() == miscValue)
4867 return true;
4868 return false;
4869 });
4870}
4871
4873{
4874 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4875 {
4876 if (aurEff->GetMiscValue() == miscValue)
4877 return true;
4878 return false;
4879 });
4880}
4881
4883{
4884 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4885 {
4886 if (aurEff->GetMiscValue() == miscValue)
4887 return true;
4888 return false;
4889 });
4890}
4891
4893{
4894 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4895 {
4896 if (aurEff->IsAffectingSpell(affectedSpell))
4897 return true;
4898 return false;
4899 });
4900}
4901
4902float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4903{
4904 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4905 {
4906 if (aurEff->IsAffectingSpell(affectedSpell))
4907 return true;
4908 return false;
4909 });
4910}
4911
4913{
4914 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4915 {
4916 if (aurEff->IsAffectingSpell(affectedSpell))
4917 return true;
4918 return false;
4919 });
4920}
4921
4923{
4924 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4925 {
4926 if (aurEff->IsAffectingSpell(affectedSpell))
4927 return true;
4928 return false;
4929 });
4930}
4931
4933{
4934 float modPos = 0.0f;
4935 float modNeg = 0.0f;
4936
4937 // these auras are always positive
4939 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
4940 {
4941 if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() > 0)
4942 return true;
4943 return false;
4944 });
4945
4946 modNeg = GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
4947 {
4948 if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() < 0)
4949 return true;
4950 return false;
4951 });
4952
4954 modPos *= factor;
4955 modNeg *= factor;
4956
4959}
4960
4962{
4963 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
4965 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
4967}
4968
4970{
4971 float modPos = 0.0f;
4972 float modNeg = 0.0f;
4973 float factor = 0.0f;
4974
4975 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
4976
4977 // includes value from items and enchantments
4978 float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
4979 if (modValue > 0.f)
4980 modPos += modValue;
4981 else
4982 modNeg += modValue;
4983
4984 if (IsGuardian())
4985 {
4986 modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
4987 if (modValue > 0.f)
4988 modPos += modValue;
4989 else
4990 modNeg += modValue;
4991 }
4992
4993 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
4994 {
4995 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
4996 return true;
4997 return false;
4998 });
4999
5000 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5001 {
5002 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5003 return true;
5004 return false;
5005 });
5006
5007 factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
5008 {
5009 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5010 return true;
5011 return false;
5012 });
5013
5014 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
5015 {
5016 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5017 return true;
5018 return false;
5019 });
5020
5021 modPos *= factor;
5022 modNeg *= factor;
5023
5026}
5027
5029{
5030 m_dynObj.push_back(dynObj);
5031}
5032
5034{
5035 m_dynObj.remove(dynObj);
5036}
5037
5039{
5040 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5041 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5042}
5043
5044std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5045{
5046 std::vector<DynamicObject*> dynamicobjects;
5047 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5048 if ((*i)->GetSpellId() == spellId)
5049 dynamicobjects.push_back(*i);
5050
5051 return dynamicobjects;
5052}
5053
5055{
5056 if (m_dynObj.empty())
5057 return;
5058 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5059 {
5060 DynamicObject* dynObj = *i;
5061 if (dynObj->GetSpellId() == spellId)
5062 {
5063 dynObj->Remove();
5064 i = m_dynObj.begin();
5065 }
5066 else
5067 ++i;
5068 }
5069}
5070
5072{
5073 while (!m_dynObj.empty())
5074 m_dynObj.front()->Remove();
5075}
5076
5078{
5079 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5080 return gameobjects.empty() ? nullptr : gameobjects.front();
5081}
5082
5083std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5084{
5085 std::vector<GameObject*> gameobjects;
5086 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5087 if ((*i)->GetSpellId() == spellId)
5088 gameobjects.push_back(*i);
5089
5090 return gameobjects;
5091}
5092
5094{
5095 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5096 return;
5097
5098 m_gameObj.push_back(gameObj);
5099 gameObj->SetOwnerGUID(GetGUID());
5100
5101 if (gameObj->GetSpellId())
5102 {
5103 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId());
5104 // Need disable spell use for owner
5105 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5106 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5107 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5108 }
5109}
5110
5111void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5112{
5113 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5114 return;
5115
5117
5118 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
5119 {
5120 if (m_ObjectSlot[i] == gameObj->GetGUID())
5121 {
5122 m_ObjectSlot[i].Clear();
5123 break;
5124 }
5125 }
5126
5127 // GO created by some spell
5128 if (uint32 spellid = gameObj->GetSpellId())
5129 {
5130 RemoveAurasDueToSpell(spellid);
5131
5132 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
5133 // Need activate spell use for owner
5134 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5135 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5136 GetSpellHistory()->SendCooldownEvent(createBySpell);
5137 }
5138
5139 m_gameObj.remove(gameObj);
5140
5141 if (del)
5142 {
5143 gameObj->SetRespawnTime(0);
5144 gameObj->Delete();
5145 }
5146}
5147
5148void Unit::RemoveGameObject(uint32 spellid, bool del)
5149{
5150 if (m_gameObj.empty())
5151 return;
5152 GameObjectList::iterator i, next;
5153 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
5154 {
5155 next = i;
5156 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5157 {
5158 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5159 if (del)
5160 {
5161 (*i)->SetRespawnTime(0);
5162 (*i)->Delete();
5163 }
5164
5165 next = m_gameObj.erase(i);
5166 }
5167 else
5168 ++next;
5169 }
5170}
5171
5173{
5174 // remove references to unit
5175 while (!m_gameObj.empty())
5176 {
5177 GameObjectList::iterator i = m_gameObj.begin();
5178 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5179 (*i)->SetRespawnTime(0);
5180 (*i)->Delete();
5181 m_gameObj.erase(i);
5182 }
5183}
5184
5186{
5187 WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size
5188 data << log->target->GetPackGUID();
5189 data << log->attacker->GetPackGUID();
5190 data << uint32(log->SpellID);
5191 data << uint32(log->damage); // damage amount
5192 int32 overkill = log->damage - log->target->GetHealth();
5193 data << uint32(overkill > 0 ? overkill : 0); // overkill
5194 data << uint8 (log->schoolMask); // damage school
5195 data << uint32(log->absorb); // AbsorbedDamage
5196 data << uint32(log->resist); // resist
5197 data << uint8 (log->periodicLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
5198 data << uint8 (log->unused); // unused
5199 data << uint32(log->blocked); // blocked
5200 data << uint32(log->HitInfo);
5202 //if (log->HitInfo & SPELL_HIT_TYPE_CRIT_DEBUG)
5203 //{
5204 // data << float(log->CritRoll);
5205 // data << float(log->CritNeeded);
5206 //}
5207 //if (log->HitInfo & SPELL_HIT_TYPE_HIT_DEBUG)
5208 //{
5209 // data << float(log->HitRoll);
5210 // data << float(log->HitNeeded);
5211 //}
5212 //if (log->HitInfo & SPELL_HIT_TYPE_ATTACK_TABLE_DEBUG)
5213 //{
5214 // data << float(log->MissChance);
5215 // data << float(log->DodgeChance);
5216 // data << float(log->ParryChance);
5217 // data << float(log->BlockChance);
5218 // data << float(log->GlanceChance);
5219 // data << float(log->CrushChance);
5220 //}
5221 SendMessageToSet(&data, true);
5222}
5223
5224void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 spellID, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 absorbedDamage, uint32 resist, bool isPeriodic, uint32 blocked, bool criticalHit, bool split)
5225{
5226 SpellNonMeleeDamage log(this, target, spellID, damageSchoolMask);
5227 log.damage = damage - absorbedDamage - resist - blocked;
5228 log.absorb = absorbedDamage;
5229 log.resist = resist;
5230 log.periodicLog = isPeriodic;
5231 log.blocked = blocked;
5232 log.HitInfo = 0;
5233 if (criticalHit)
5235 if (split)
5238}
5239
5240/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5241{
5242 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5243 if (typeMaskActor && actor)
5244 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5245
5246 if (typeMaskActionTarget && actionTarget)
5247 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5248
5249 if (actor)
5250 actor->TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5251}
5252
5254{
5255 AuraEffect const* aura = pInfo->auraEff;
5256
5258 data << GetPackGUID();
5259 data << aura->GetCasterGUID().WriteAsPacked();
5260 data << uint32(aura->GetId()); // spellId
5261 data << uint32(1); // count
5262 data << uint32(aura->GetAuraType()); // auraId
5263 switch (aura->GetAuraType())
5264 {
5267 data << uint32(pInfo->damage); // damage
5268 data << uint32(pInfo->overDamage); // overkill?
5269 data << uint32(aura->GetSpellInfo()->GetSchoolMask());
5270 data << uint32(pInfo->absorb); // absorb
5271 data << uint32(pInfo->resist); // resist
5272 data << uint8(pInfo->critical); // new 3.1.2 critical tick
5273 break;
5276 data << uint32(pInfo->damage); // damage
5277 data << uint32(pInfo->overDamage); // overheal
5278 data << uint32(pInfo->absorb); // absorb
5279 data << uint8(pInfo->critical); // new 3.1.2 critical tick
5280 break;
5283 data << uint32(aura->GetMiscValue()); // power type
5284 data << uint32(pInfo->damage); // damage
5285 break;
5287 data << uint32(aura->GetMiscValue()); // power type
5288 data << uint32(pInfo->damage); // amount
5289 data << float(pInfo->multiplier); // gain multiplier
5290 break;
5291 default:
5292 TC_LOG_ERROR("entities.unit", "Unit::SendPeriodicAuraLog: unknown aura {}", uint32(aura->GetAuraType()));
5293 return;
5294 }
5295
5296 SendMessageToSet(&data, true);
5297}
5298
5300{
5301 WorldPacket data(SMSG_PROCRESIST, 8+8+4+1);
5302 data << GetGUID();
5303 data << target->GetGUID();
5304 data << uint32(spellId);
5305 data << uint8(0); // bool - log format: 0-default, 1-debug
5306 SendMessageToSet(&data, true);
5307}
5308
5310{
5312 data << GetGUID();
5313 data << target->GetGUID();
5314 data << uint32(spellId);
5315 data << uint8(0); // bool - log format: 0-default, 1-debug
5316 SendMessageToSet(&data, true);
5317}
5318
5320{
5321 uint32 count = 1;
5322 if (damageInfo->Damages[1].Damage || damageInfo->Damages[1].Absorb || damageInfo->Damages[1].Resist)
5323 ++count;
5324
5325 // guess size
5326 size_t const maxsize = 4+5+5+4+4+1+(4+4+4)*2+4*2+4*2+1+4+4+4+4+4*12;
5328
5329 data << uint32(damageInfo->HitInfo);
5330 data << damageInfo->Attacker->GetPackGUID();
5331 data << damageInfo->Target->GetPackGUID();
5332 data << uint32(damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage); // Full damage
5333 int32 overkill = damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage - damageInfo->Target->GetHealth();
5334 data << uint32(overkill < 0 ? 0 : overkill); // Overkill
5335 data << uint8(count); // Sub damage count
5336
5337 for (uint32 i = 0; i < count; ++i)
5338 {
5339 data << uint32(damageInfo->Damages[i].DamageSchoolMask); // School of sub damage
5340 data << float(damageInfo->Damages[i].Damage); // sub damage
5341 data << uint32(damageInfo->Damages[i].Damage); // Sub Damage
5342 }
5343
5345 {
5346 for (uint32 i = 0; i < count; ++i)
5347 data << uint32(damageInfo->Damages[i].Absorb); // Absorb
5348 }
5349
5351 {
5352 for (uint32 i = 0; i < count; ++i)
5353 data << uint32(damageInfo->Damages[i].Resist); // Resist
5354 }
5355
5356 data << uint8(damageInfo->TargetState);
5357 data << uint32(0); // Unknown attackerstate
5358 data << uint32(0); // Melee spellid
5359
5360 if (damageInfo->HitInfo & HITINFO_BLOCK)
5361 data << uint32(damageInfo->Blocked);
5362
5363 if (damageInfo->HitInfo & HITINFO_RAGE_GAIN)
5364 data << uint32(0);
5365
5367 if (damageInfo->HitInfo & HITINFO_UNK1)
5368 {
5369 data << uint32(0);
5370 data << float(0);
5371 data << float(0);
5372 data << float(0);
5373 data << float(0);
5374 data << float(0);
5375 data << float(0);
5376 data << float(0);
5377 data << float(0);
5378 data << float(0); // Found in a loop with 1 iteration
5379 data << float(0); // ditto ^
5380 data << uint32(0);
5381 }
5382
5383 SendMessageToSet(&data, true);
5384}
5385
5386void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
5387{
5388 CalcDamageInfo dmgInfo;
5389 dmgInfo.HitInfo = HitInfo;
5390 dmgInfo.Attacker = this;
5391 dmgInfo.Target = target;
5392
5393 dmgInfo.Damages[0].Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5394 dmgInfo.Damages[0].DamageSchoolMask = damageSchoolMask;
5395 dmgInfo.Damages[0].Absorb = AbsorbDamage;
5396 dmgInfo.Damages[0].Resist = Resist;
5397
5398 dmgInfo.Damages[1].Damage = 0;
5399 dmgInfo.Damages[1].DamageSchoolMask = 0;
5400 dmgInfo.Damages[1].Absorb = 0;
5401 dmgInfo.Damages[1].Resist = 0;
5402
5403 dmgInfo.TargetState = TargetState;
5404 dmgInfo.Blocked = BlockedAmount;
5405 SendAttackStateUpdate(&dmgInfo);
5406}
5407
5408void Unit::SetPowerType(Powers new_powertype, bool sendUpdate/* = true*/)
5409{
5410 if (GetPowerType() == new_powertype)
5411 return;
5412
5414
5415 if (!sendUpdate)
5416 return;
5417
5418 if (GetTypeId() == TYPEID_PLAYER)
5419 {
5420 if (ToPlayer()->GetGroup())
5422 }
5423 else if (Pet* pet = ToCreature()->ToPet())
5424 {
5425 if (pet->isControlled())
5426 {
5427 Unit* owner = GetOwner();
5428 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
5430 }
5431 }
5432
5433 // Update max power
5434 UpdateMaxPower(new_powertype);
5435
5436 // Update current power
5437 switch (new_powertype)
5438 {
5439 case POWER_MANA: // Keep the same (druid form switching...)
5440 case POWER_ENERGY:
5441 break;
5442 case POWER_RAGE: // Reset to zero
5443 SetPower(POWER_RAGE, 0);
5444 break;
5445 case POWER_FOCUS: // Make it full
5446 SetFullPower(new_powertype);
5447 break;
5448 default:
5449 break;
5450 }
5451}
5452
5454{
5455 Powers displayPower = POWER_MANA;
5456 switch (GetShapeshiftForm())
5457 {
5458 case FORM_GHOUL:
5459 case FORM_CAT:
5460 displayPower = POWER_ENERGY;
5461 break;
5462 case FORM_BEAR:
5463 case FORM_DIREBEAR:
5464 displayPower = POWER_RAGE;
5465 break;
5466 case FORM_TRAVEL:
5467 case FORM_GHOSTWOLF:
5468 displayPower = POWER_MANA;
5469 break;
5470 default:
5471 {
5472 if (GetTypeId() == TYPEID_PLAYER)
5473 {
5474 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5475 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5476 displayPower = Powers(cEntry->DisplayPower);
5477 }
5478 else if (GetTypeId() == TYPEID_UNIT)
5479 {
5480 if (Vehicle* vehicle = GetVehicleKit())
5481 {
5482 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID))
5483 displayPower = Powers(powerDisplay->ActualType);
5484 else if (GetClass() == CLASS_ROGUE)
5485 displayPower = POWER_ENERGY;
5486 }
5487 else if (Pet* pet = ToPet())
5488 {
5489 if (pet->getPetType() == HUNTER_PET) // Hunter pets have focus
5490 displayPower = POWER_FOCUS;
5491 else if (pet->IsPetGhoul() || pet->IsRisenAlly()) // DK pets have energy
5492 displayPower = POWER_ENERGY;
5493 }
5494 }
5495 break;
5496 }
5497 }
5498
5499 SetPowerType(displayPower);
5500}
5501
5502void Unit::_addAttacker(Unit* pAttacker)
5503{
5504 m_attackers.insert(pAttacker);
5505}
5506
5508{
5509 m_attackers.erase(pAttacker);
5510}
5511
5512Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5513{
5514 if (!IsEngaged())
5515 return nullptr;
5516
5517 if (Unit* victim = GetVictim())
5518 if ((!IsPet() && !IsCharmerOrSelfPlayer()) || IsInCombatWith(victim))
5519 return victim;
5520
5521 CombatManager const& mgr = GetCombatManager();
5522 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5523 Unit* owner = GetCharmerOrOwner();
5524 if (mgr.HasPvPCombat())
5525 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5526 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5527 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5528 if (mgr.HasPvECombat())
5529 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5530 if (owner && (owner->GetCombatManager().HasPvECombat()))
5531 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5532 return nullptr;
5533}
5534
5535bool Unit::Attack(Unit* victim, bool meleeAttack)
5536{
5537 if (!victim || victim == this)
5538 return false;
5539
5540 // dead units can neither attack nor be attacked
5541 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5542 return false;
5543
5544 // player cannot attack in mount state
5545 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5546 return false;
5547
5548 Creature* creature = ToCreature();
5549 // creatures cannot attack while evading
5550 if (creature && creature->IsInEvadeMode())
5551 return false;
5552
5553 // nobody can attack GM in GM-mode
5554 if (victim->GetTypeId() == TYPEID_PLAYER)
5555 {
5556 if (victim->ToPlayer()->IsGameMaster())
5557 return false;
5558 }
5559 else
5560 {
5561 if (victim->ToCreature()->IsEvadingAttacks())
5562 return false;
5563 }
5564
5565 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5568
5569 if (m_attacking)
5570 {
5571 if (m_attacking == victim)
5572 {
5573 // switch to melee attack from ranged/magic
5574 if (meleeAttack)
5575 {
5577 {
5579 SendMeleeAttackStart(victim);
5580 return true;
5581 }
5582 }
5584 {
5586 SendMeleeAttackStop(victim);
5587 return true;
5588 }
5589 return false;
5590 }
5591
5592 // switch target
5594 if (!meleeAttack)
5596 }
5597
5598 if (m_attacking)
5600
5601 m_attacking = victim;
5603
5604 // Set our target
5605 SetTarget(victim->GetGUID());
5606
5607 if (meleeAttack)
5609
5610 // set position before any AI calls/assistance
5611 //if (GetTypeId() == TYPEID_UNIT)
5612 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5613
5614 if (creature && !IsControlledByPlayer())
5615 {
5616 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5617
5619 creature->CallAssistance();
5620
5621 // Remove emote state - will be restored on creature reset
5623 }
5624
5625 // delay offhand weapon attack by 50% of the base attack time
5628
5629 if (meleeAttack)
5630 SendMeleeAttackStart(victim);
5631
5632 // Let the pet know we've started attacking someting. Handles melee attacks only
5633 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5634 if (GetTypeId() == TYPEID_PLAYER)
5635 {
5636 for (Unit* controlled : m_Controlled)
5637 if (Creature* cControlled = controlled->ToCreature())
5638 if (CreatureAI* controlledAI = cControlled->AI())
5639 controlledAI->OwnerAttacked(victim);
5640 }
5641
5642 return true;
5643}
5644
5646{
5647 if (!m_attacking)
5648 return false;
5649
5650 Unit* victim = m_attacking;
5651
5653 m_attacking = nullptr;
5654
5655 // Clear our target
5657
5659
5661
5662 // reset only at real combat stop
5663 if (Creature* creature = ToCreature())
5664 {
5665 creature->SetNoCallAssistance(false);
5666 }
5667
5668 SendMeleeAttackStop(victim);
5669
5670 return true;
5671}
5672
5674{
5675 // iterate attackers
5676 UnitVector toRemove;
5677 AttackerSet const& attackers = getAttackers();
5678 for (Unit* attacker : attackers)
5679 if (!attacker->IsValidAttackTarget(this))
5680 toRemove.push_back(attacker);
5681
5682 for (Unit* attacker : toRemove)
5683 attacker->AttackStop();
5684
5685 // remove our own victim
5686 if (Unit* victim = GetVictim())
5687 if (!IsValidAttackTarget(victim))
5688 AttackStop();
5689}
5690
5691void Unit::CombatStop(bool includingCast, bool mutualPvP)
5692{
5693 if (includingCast && IsNonMeleeSpellCast(false))
5695
5696 AttackStop();
5698 if (GetTypeId() == TYPEID_PLAYER)
5699 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
5700
5701 if (mutualPvP)
5702 ClearInCombat();
5703 else
5704 { // vanish and brethren are weird
5707 }
5708}
5709
5710void Unit::CombatStopWithPets(bool includingCast)
5711{
5712 CombatStop(includingCast);
5713
5714 for (Unit* minion : m_Controlled)
5715 minion->CombatStop(includingCast);
5716}
5717
5719{
5721 return true;
5722
5723 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
5724 if ((*itr)->isAttackingPlayer())
5725 return true;
5726
5727 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
5728 if (!m_SummonSlot[i].IsEmpty())
5729 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
5730 if (summon->isAttackingPlayer())
5731 return true;
5732
5733 return false;
5734}
5735
5737{
5738 while (!m_attackers.empty())
5739 {
5740 AttackerSet::iterator iter = m_attackers.begin();
5741 if (!(*iter)->AttackStop())
5742 {
5743 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
5744 m_attackers.erase(iter);
5745 }
5746 }
5747}
5748
5750{
5751 if (apply)
5752 {
5753 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
5754 {
5755 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
5756 if (GetTypeId() == TYPEID_PLAYER)
5757 {
5758 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
5759 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
5760 {
5761 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
5762 continue;
5763 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
5764 if (!spellInfo || !spellInfo->IsPassive())
5765 continue;
5766 if (spellInfo->CasterAuraState == uint32(flag))
5767 CastSpell(this, itr->first, true);
5768 }
5769 }
5770 else if (Pet* pet = ToCreature()->ToPet())
5771 {
5772 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
5773 {
5774 if (itr->second.state == PETSPELL_REMOVED)
5775 continue;
5776 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
5777 if (!spellInfo || !spellInfo->IsPassive())
5778 continue;
5779 if (spellInfo->CasterAuraState == uint32(flag))
5780 CastSpell(this, itr->first, true);
5781 }
5782 }
5783 }
5784 }
5785 else
5786 {
5787 if (HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
5788 {
5789 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
5790
5792 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
5793 {
5794 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
5795 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGE))
5796 RemoveAura(itr);
5797 else
5798 ++itr;
5799 }
5800 }
5801 }
5802}
5803
5805{
5807 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
5808 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
5809 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
5810 auraStates |= (1 << (itr->first - 1));
5811
5812 return auraStates;
5813}
5814
5815bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
5816{
5817 if (Caster)
5818 {
5819 if (spellProto)
5820 {
5822 return true;
5823 }
5824
5825 // Check per caster aura state
5826 // If aura with aurastate by caster not found return false
5827 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
5828 {
5829 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
5830 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
5831 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
5832 return true;
5833 return false;
5834 }
5835 }
5836
5837 return HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1));
5838}
5839
5841{
5842 if (GetOwnerGUID() == owner)
5843 return;
5844
5846 if (!owner)
5847 return;
5848
5849 // Update owner dependent fields
5850 Player* player = ObjectAccessor::GetPlayer(*this, owner);
5851 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
5852 return;
5853
5855
5856 UpdateData udata;
5857 WorldPacket packet;
5858 BuildValuesUpdateBlockForPlayer(&udata, player);
5859 udata.BuildPacket(&packet);
5860 player->SendDirectMessage(&packet);
5861
5863}
5864
5866{
5868 if (!guid.IsEmpty())
5869 {
5870 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
5871 return master->GetControllingPlayer();
5872 return nullptr;
5873 }
5874 else
5875 return const_cast<Player*>(ToPlayer());
5876}
5877
5879{
5880 ObjectGuid pet_guid = GetMinionGUID();
5881 if (!pet_guid.IsEmpty())
5882 {
5883 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
5884 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
5885 return (Minion*)pet;
5886
5887 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
5888 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
5889 }
5890
5891 return nullptr;
5892}
5893
5895{
5896 ObjectGuid pet_guid = GetPetGUID();
5897 if (!pet_guid.IsEmpty())
5898 {
5899 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
5900 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
5901 return (Guardian*)pet;
5902
5903 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
5904 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
5905 }
5906
5907 return nullptr;
5908}
5909
5910void Unit::SetMinion(Minion *minion, bool apply)
5911{
5912 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
5913
5914 if (apply)
5915 {
5916 if (!minion->GetOwnerGUID().IsEmpty())
5917 {
5918 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
5919 return;
5920 }
5921
5922 if (!IsInWorld())
5923 {
5924 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
5925 return;
5926 }
5927
5928 minion->SetOwnerGUID(GetGUID());
5929
5930 m_Controlled.insert(minion);
5931
5932 if (GetTypeId() == TYPEID_PLAYER)
5933 {
5934 minion->m_ControlledByPlayer = true;
5936 }
5937
5938 // Can only have one pet. If a new one is summoned, dismiss the old one.
5939 if (minion->IsGuardianPet())
5940 {
5941 if (Guardian* oldPet = GetGuardianPet())
5942 {
5943 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
5944 {
5945 // remove existing minion pet
5946 if (Pet* oldPetAsPet = oldPet->ToPet())
5947 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
5948 else
5949 oldPet->UnSummon();
5950 SetPetGUID(minion->GetGUID());
5952 }
5953 }
5954 else
5955 {
5956 SetPetGUID(minion->GetGUID());
5958 }
5959 }
5960
5963
5964 if (minion->m_Properties && minion->m_Properties->Title == SUMMON_TYPE_MINIPET)
5965 SetCritterGUID(minion->GetGUID());
5966
5967 // PvP, FFAPvP
5969
5970 // FIXME: hack, speed must be set only at follow
5971 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
5972 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
5973 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
5974
5975 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
5976 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5977 if (spellInfo && spellInfo->IsCooldownStartedOnEvent())
5978 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
5979 }
5980 else
5981 {
5982 if (minion->GetOwnerGUID() != GetGUID())
5983 {
5984 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
5985 return;
5986 }
5987
5988 m_Controlled.erase(minion);
5989
5990 if (minion->m_Properties && minion->m_Properties->Title == SUMMON_TYPE_MINIPET)
5991 if (GetCritterGUID() == minion->GetGUID())
5993
5994 if (minion->IsGuardianPet())
5995 {
5996 if (GetPetGUID() == minion->GetGUID())
5998 }
5999 else if (minion->IsTotem())
6000 {
6001 // All summoned by totem minions must disappear when it is removed.
6002 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell()))
6003 {
6004 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
6005 {
6006 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
6007 continue;
6008
6009 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
6010 }
6011 }
6012 }
6013
6014 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
6015 // Remove infinity cooldown
6016 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6017 GetSpellHistory()->SendCooldownEvent(spellInfo);
6018
6019 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6020 {
6022 {
6023 // Check if there is another minion
6024 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6025 {
6026 // do not use this check, creature do not have charm guid
6027 //if (GetCharmedGUID() == (*itr)->GetGUID())
6028 if (GetGUID() == (*itr)->GetCharmerGUID())
6029 continue;
6030
6031 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
6032 if ((*itr)->GetOwnerGUID() != GetGUID())
6033 {
6034 OutDebugInfo();
6035 (*itr)->OutDebugInfo();
6036 ABORT();
6037 }
6038 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
6039
6040 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
6041 continue;
6042
6043 if (AddGuidValue(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
6044 {
6045 // show another pet bar if there is no charm bar
6046 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
6047 {
6048 if ((*itr)->IsPet())
6050 else
6052 }
6053 }
6054 break;
6055 }
6056 }
6057 }
6058 }
6060}
6061
6062void Unit::GetAllMinionsByEntry(std::list<Creature*>& Minions, uint32 entry)
6063{
6064 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6065 {
6066 Unit* unit = *itr;
6067 ++itr;
6068 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6069 && unit->IsSummon()) // minion, actually
6070 Minions.push_back(unit->ToCreature());
6071 }
6072}
6073
6075{
6076 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6077 {
6078 Unit* unit = *itr;
6079 ++itr;
6080 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6081 && unit->IsSummon()) // minion, actually
6082 unit->ToTempSummon()->UnSummon();
6083 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6084 }
6085}
6086
6087void Unit::SetCharm(Unit* charm, bool apply)
6088{
6089 if (apply)
6090 {
6091 if (GetTypeId() == TYPEID_PLAYER)
6092 {
6094 "Player %s is trying to charm unit %u, but it already has a charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6095 m_charmed = charm;
6096
6097 charm->m_ControlledByPlayer = true;
6100 }
6101 else
6102 charm->m_ControlledByPlayer = false;
6103
6104 // PvP, FFAPvP
6106
6108 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6109 charm->m_charmer = this;
6110
6113 charm->SetWalk(false);
6114
6115 m_Controlled.insert(charm);
6116 }
6117 else
6118 {
6120
6121 if (GetTypeId() == TYPEID_PLAYER)
6122 {
6124 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6125 m_charmed = nullptr;
6126 }
6127
6129 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6130 charm->m_charmer = nullptr;
6131
6132 if (charm->GetTypeId() == TYPEID_PLAYER)
6133 {
6134 charm->m_ControlledByPlayer = true;
6136 charm->ToPlayer()->UpdatePvPState();
6137 }
6138 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6139 {
6140 charm->m_ControlledByPlayer = true;
6142 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6143 }
6144 else
6145 {
6146 charm->m_ControlledByPlayer = false;
6149 }
6150
6151 if (charm->IsWalking() != _isWalkingBeforeCharm)
6153
6154 if (charm->GetTypeId() == TYPEID_PLAYER
6156 || charm->GetOwnerGUID() != GetGUID())
6157 {
6158 m_Controlled.erase(charm);
6159 }
6160 }
6162}
6163
6164/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6165{
6166 int32 gain = 0;
6167 Unit* healer = healInfo.GetHealer();
6168 Unit* victim = healInfo.GetTarget();
6169 uint32 addhealth = healInfo.GetHeal();
6170
6171 if (UnitAI* victimAI = victim->GetAI())
6172 victimAI->HealReceived(healer, addhealth);
6173
6174 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6175 healerAI->HealDone(victim, addhealth);
6176
6177 if (addhealth)
6178 gain = victim->ModifyHealth(int32(addhealth));
6179
6180 // Hook for OnHeal Event
6181 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6182
6183 Unit* unit = healer;
6184 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6185 unit = healer->GetOwner();
6186
6187 if (unit)
6188 {
6189 if (Player* player = unit->ToPlayer())
6190 {
6191 if (Battleground* bg = player->GetBattleground())
6192 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6193
6194 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6195 if (gain)
6196 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
6197
6198 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth);
6199 }
6200 }
6201
6202 if (Player* player = victim->ToPlayer())
6203 {
6204 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
6205 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
6206 }
6207
6208 if (gain)
6209 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6210}
6211
6212bool Unit::IsMagnet() const
6213{
6214 // Grounding Totem
6216 return true;
6217
6218 return false;
6219}
6220
6222{
6224 for (AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
6225 {
6226 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6227 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6228 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6229 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6230 if (roll_chance_i((*i)->GetAmount()))
6231 {
6232 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6233 return magnet;
6234 }
6235 }
6236 return victim;
6237}
6238
6240{
6241 // Sequence: charmed, pet, other guardians
6242 Unit* unit = GetCharmed();
6243 if (!unit)
6244 {
6245 ObjectGuid guid = GetMinionGUID();
6246 if (!guid.IsEmpty())
6247 unit = ObjectAccessor::GetUnit(*this, guid);
6248 }
6249
6250 return unit;
6251}
6252
6254{
6255 // possessed pet and vehicle
6256 if (GetTypeId() == TYPEID_PLAYER)
6258
6259 while (!m_Controlled.empty())
6260 {
6261 Unit* target = *m_Controlled.begin();
6262 m_Controlled.erase(m_Controlled.begin());
6263 if (target->GetCharmerGUID() == GetGUID())
6264 target->RemoveCharmAuras();
6265 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6266 target->ToTempSummon()->UnSummon();
6267 else
6268 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6269 }
6270 if (!GetPetGUID().IsEmpty())
6271 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6272 if (!GetMinionGUID().IsEmpty())
6273 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6274 if (!GetCharmedGUID().IsEmpty())
6275 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6276 if (!IsPet()) // pets don't use the flag for this
6277 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6278}
6279
6284
6286{
6287 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6288}
6289
6291{
6292 if (Unit* u = GetCharmed())
6293 return u->isPossessed();
6294 else
6295 return false;
6296}
6297
6299{
6300 if (IsCharmed())
6301 return GetCharmer();
6302 else
6303 return const_cast<Unit*>(this);
6304}
6305
6307{
6308 Player* player = nullptr;
6309 if (GetTypeId() == TYPEID_PLAYER)
6310 player = ToPlayer();
6311 // Should we enable this also for charmed units?
6312 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6313 player = GetOwner()->ToPlayer();
6314
6315 if (!player)
6316 return nullptr;
6317 Group* group = player->GetGroup();
6318 // When there is no group check pet presence
6319 if (!group)
6320 {
6321 // We are pet now, return owner
6322 if (player != this)
6323 return IsWithinDistInMap(player, radius) ? player : nullptr;
6324 Unit* pet = GetGuardianPet();
6325 // No pet, no group, nothing to return
6326 if (!pet)
6327 return nullptr;
6328 // We are owner now, return pet
6329 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6330 }
6331
6332 std::vector<Unit*> nearMembers;
6333 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6334 nearMembers.reserve(group->GetMembersCount() * 2);
6335
6336 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
6337 if (Player* Target = itr->GetSource())
6338 {
6339 // IsHostileTo check duel and controlled by enemy
6340 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6341 nearMembers.push_back(Target);
6342
6343 // Push player's pet to vector
6344 if (Unit* pet = Target->GetGuardianPet())
6345 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6346 nearMembers.push_back(pet);
6347 }
6348
6349 if (nearMembers.empty())
6350 return nullptr;
6351
6352 uint32 randTarget = urand(0, nearMembers.size()-1);
6353 return nearMembers[randTarget];
6354}
6355
6356// only called in Player::SetSeer
6357// so move it to Player?
6359{
6360 if (m_sharedVision.empty())
6361 {
6362 setActive(true);
6364 }
6365 m_sharedVision.push_back(player);
6366}
6367
6368// only called in Player::SetSeer
6370{
6371 m_sharedVision.remove(player);
6372 if (m_sharedVision.empty())
6373 {
6374 setActive(false);
6376 }
6377}
6378
6383
6391
6393{
6394 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6395 {
6396 if (!m_SummonSlot[i])
6397 continue;
6398
6399 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6400 if (OldTotem->IsSummon())
6401 OldTotem->ToTempSummon()->UnSummon();
6402 }
6403}
6404
6405void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6406{
6407 // we guess size
6408 WorldPacket data(SMSG_SPELLHEALLOG, 8 + 8 + 4 + 4 + 4 + 4 + 1 + 1);
6409 data << healInfo.GetTarget()->GetPackGUID();
6410 data << healInfo.GetHealer()->GetPackGUID();
6411 data << uint32(healInfo.GetSpellInfo()->Id);
6412 data << uint32(healInfo.GetHeal());
6413 data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal());
6414 data << uint32(healInfo.GetAbsorb()); // Absorb amount
6415 data << uint8(critical ? 1 : 0);
6416 data << uint8(0); // unused
6417 SendMessageToSet(&data, true);
6418}
6419
6420int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6421{
6422 // calculate heal absorb and reduce healing
6423 Unit::CalcHealAbsorb(healInfo);
6424 Unit::DealHeal(healInfo);
6425 SendHealSpellLog(healInfo, critical);
6426 return healInfo.GetEffectiveHeal();
6427}
6428
6429void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellId, int32 damage, Powers powerType)
6430{
6431 WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
6432 data << victim->GetPackGUID();
6433 data << GetPackGUID();
6434 data << uint32(spellId);
6435 data << uint32(powerType);
6436 data << int32(damage);
6437 SendMessageToSet(&data, true);
6438}
6439
6440void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers powerType)
6441{
6442 if (SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId))
6443 EnergizeBySpell(victim, info, damage, powerType);
6444}
6445
6446void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6447{
6448 victim->ModifyPower(powerType, damage, false);
6449 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage)/2, spellInfo, true);
6450 SendEnergizeSpellLog(victim, spellInfo->Id, damage, powerType);
6451}
6452
6453uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
6454{
6455 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6456 return pdamage;
6457
6458 // Some spells don't benefit from done mods
6459 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
6460 return pdamage;
6461
6462 // For totems get damage bonus from owner
6463 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6464 if (Unit* owner = GetOwner())
6465 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, donePctTotal, stack);
6466
6467 float ApCoeffMod = 1.0f;
6468 int32 DoneTotal = 0;
6469 float DoneTotalMod = donePctTotal ? *donePctTotal : SpellDamagePctDone(victim, spellProto, damagetype);
6470
6471 // done scripted mod (take it from owner)
6472 Unit const* owner = GetOwner() ? GetOwner() : this;
6473 DoneTotal += owner->GetTotalAuraModifier(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, [spellProto](AuraEffect const* aurEff) -> bool
6474 {
6475 if (!aurEff->IsAffectingSpell(spellProto))
6476 return false;
6477
6478 switch (aurEff->GetMiscValue())
6479 {
6480 case 4418: // Increased Shock Damage
6481 case 4554: // Increased Lightning Damage
6482 case 4555: // Improved Moonfire
6483 case 5142: // Increased Lightning Damage
6484 case 5147: // Improved Consecration / Libram of Resurgence
6485 case 5148: // Idol of the Shooting Star
6486 case 6008: // Increased Lightning Damage
6487 case 8627: // Totem of Hex
6488 return true;
6489 default:
6490 break;
6491 }
6492
6493 return false;
6494 });
6495
6496 // Some spells don't benefit from pct done mods
6499
6500 // Custom scripted damage
6501 switch (spellProto->SpellFamilyName)
6502 {
6504 // Impurity (dummy effect)
6505 if (GetTypeId() == TYPEID_PLAYER)
6506 {
6507 PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
6508 for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
6509 {
6510 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
6511 continue;
6512
6513 switch (itr->first)
6514 {
6515 case 49220:
6516 case 49633:
6517 case 49635:
6518 case 49636:
6519 case 49638:
6520 if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
6521 AddPct(ApCoeffMod, proto->GetEffect(EFFECT_0).CalcValue());
6522 break;
6523 }
6524 }
6525 }
6526 break;
6527 }
6528
6529 // Done fixed damage bonus auras
6530 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6531 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6532 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6533
6534 // Pets just add their bonus damage to their spell damage
6535 // note that their spell damage is just gain of their own auras
6537 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6538
6539 // Check for table values
6540 float coeff = spellEffectInfo.BonusCoefficient;
6541 if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
6542 {
6543 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
6545 APbonus += GetTotalAttackPowerValue(attType);
6546
6547 if (damagetype == DOT)
6548 {
6549 coeff = bonus->dot_damage;
6550 if (bonus->ap_dot_bonus > 0)
6551 DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
6552 }
6553 else
6554 {
6555 coeff = bonus->direct_damage;
6556 if (bonus->ap_bonus > 0)
6557 DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
6558 }
6559 }
6560 else
6561 {
6562 // No bonus damage for SPELL_DAMAGE_CLASS_NONE class spells by default
6563 if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
6564 return uint32(std::max(pdamage * DoneTotalMod, 0.0f));
6565 }
6566
6567 // Default calculation
6568 if (DoneAdvertisedBenefit)
6569 {
6570 if (coeff < 0.f)
6571 coeff = CalculateDefaultCoefficient(spellProto, damagetype); // As wowwiki says: C = (Cast Time / 3.5)
6572
6573 float factorMod = CalculateSpellpowerCoefficientLevelPenalty(spellProto) * stack;
6574 if (Player* modOwner = GetSpellModOwner())
6575 {
6576 coeff *= 100.0f;
6577 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
6578 coeff /= 100.0f;
6579 }
6580
6581 DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
6582 }
6583
6584 float tmpDamage = float(int32(pdamage) + DoneTotal) * DoneTotalMod;
6585
6586 // apply spellmod to Done damage (flat and pct)
6587 if (Player* modOwner = GetSpellModOwner())
6588 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
6589
6590 return uint32(std::max(tmpDamage, 0.0f));
6591}
6592
6593float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const
6594{
6595 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6596 return 1.0f;
6597
6598 // Some spells don't benefit from done mods
6599 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
6600 return 1.0f;
6601
6602 // Some spells don't benefit from pct done mods
6604 return 1.0f;
6605
6606 // For totems get damage bonus from owner
6607 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6608 if (Unit* owner = GetOwner())
6609 return owner->SpellDamagePctDone(victim, spellProto, damagetype);
6610
6611 // Done total percent damage auras
6612 float DoneTotalMod = 1.0f;
6613
6614 // Pet damage?
6615 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6616 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank);
6617
6618 float maxModDamagePercentSchool = 0.0f;
6619 if (GetTypeId() == TYPEID_PLAYER)
6620 {
6621 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6622 if (spellProto->GetSchoolMask() & (1 << i))
6623 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
6624 }
6625 else
6626 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6627
6628 DoneTotalMod *= maxModDamagePercentSchool;
6629
6630 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6631
6633
6634 // bonus against aurastate
6635 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6636 {
6637 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6638 return true;
6639 return false;
6640 });
6641
6642 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6643 if (spellProto->Mechanic)
6645
6646 // done scripted mod (take it from owner)
6647 Unit const* owner = GetOwner() ? GetOwner() : this;
6648 AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
6649 for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
6650 {
6651 if (!(*i)->IsAffectingSpell(spellProto))
6652 continue;
6653
6654 switch ((*i)->GetMiscValue())
6655 {
6656 case 4920: // Molten Fury
6657 case 4919:
6658 case 6917: // Death's Embrace
6659 case 6926:
6660 case 6928:
6661 {
6662 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
6663 AddPct(DoneTotalMod, (*i)->GetAmount());
6664 break;
6665 }
6666 // Soul Siphon
6667 case 4992:
6668 case 4993:
6669 {
6670 // effect 1 m_amount
6671 int32 maxPercent = (*i)->GetAmount();
6672 // effect 0 m_amount
6673 int32 stepPercent = CalculateSpellDamage((*i)->GetSpellInfo()->GetEffect(EFFECT_0));
6674 // count affliction effects and calc additional damage in percentage
6675 int32 modPercent = 0;
6676 AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
6677 for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
6678 {
6679 Aura const* aura = itr->second->GetBase();
6680 SpellInfo const* spell = aura->GetSpellInfo();
6681 if (spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(spell->SpellFamilyFlags[1] & 0x0004071B || spell->SpellFamilyFlags[0] & 0x8044C402))
6682 continue;
6683 modPercent += stepPercent * aura->GetStackAmount();
6684 if (modPercent >= maxPercent)
6685 {
6686 modPercent = maxPercent;
6687 break;
6688 }
6689 }
6690 AddPct(DoneTotalMod, modPercent);
6691 break;
6692 }
6693 case 6916: // Death's Embrace
6694 case 6925:
6695 case 6927:
6696 if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this))
6697 AddPct(DoneTotalMod, (*i)->GetAmount());
6698 break;
6699 case 5481: // Starfire Bonus
6700 {
6701 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0, 0))
6702 AddPct(DoneTotalMod, (*i)->GetAmount());
6703 break;
6704 }
6705 // Tundra Stalker
6706 // Merciless Combat
6707 case 7277:
6708 {
6709 // Merciless Combat
6710 if ((*i)->GetSpellInfo()->SpellIconID == 2656)
6711 {
6712 if (!victim->HealthAbovePct(35))
6713 AddPct(DoneTotalMod, (*i)->GetAmount());
6714 }
6715 // Tundra Stalker
6716 else
6717 {
6718 // Frost Fever (target debuff)
6719 if (victim->HasAura(55095))
6720 AddPct(DoneTotalMod, (*i)->GetAmount());
6721 break;
6722 }
6723 break;
6724 }
6725 // Rage of Rivendare
6726 case 7293:
6727 {
6729 AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f);
6730 break;
6731 }
6732 // Twisted Faith
6733 case 7377:
6734 {
6736 AddPct(DoneTotalMod, (*i)->GetAmount());
6737 break;
6738 }
6739 // Marked for Death
6740 case 7598:
6741 case 7599:
6742 case 7600:
6743 case 7601:
6744 case 7602:
6745 {
6746 if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
6747 AddPct(DoneTotalMod, (*i)->GetAmount());
6748 break;
6749 }
6750 // Dirty Deeds
6751 case 6427:
6752 case 6428:
6753 case 6579:
6754 case 6580:
6755 {
6756 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
6757 {
6758 // effect 0 has expected value but in negative state
6759 int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
6760 AddPct(DoneTotalMod, bonus);
6761 }
6762 break;
6763 }
6764 }
6765 }
6766
6767 // Custom scripted damage
6768 switch (spellProto->SpellFamilyName)
6769 {
6770 case SPELLFAMILY_MAGE:
6771 // Ice Lance
6772 if (spellProto->SpellIconID == 186)
6773 {
6774 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6775 {
6776 // Glyph of Ice Lance
6777 if (owner->HasAura(56377) && victim->GetLevel() > owner->GetLevel())
6778 DoneTotalMod *= 4.0f;
6779 else
6780 DoneTotalMod *= 3.0f;
6781 }
6782 }
6783
6784 // Torment the weak
6785 if (spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000)
6786 {
6787 if (victim->HasAuraWithMechanic((1 << MECHANIC_SNARE) | (1 << MECHANIC_SLOW_ATTACK)))
6788 {
6790 for (AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i)
6791 {
6792 if ((*i)->GetSpellInfo()->SpellIconID == 3263)
6793 {
6794 AddPct(DoneTotalMod, (*i)->GetAmount());
6795 break;
6796 }
6797 }
6798 }
6799 }
6800 break;
6801 case SPELLFAMILY_PRIEST:
6802 // Mind Flay
6803 if (spellProto->SpellFamilyFlags[0] & 0x800000)
6804 {
6805 // Glyph of Shadow Word: Pain
6806 if (AuraEffect* aurEff = GetAuraEffect(55687, 0))
6807 // Increase Mind Flay damage if Shadow Word: Pain present on target
6809 AddPct(DoneTotalMod, aurEff->GetAmount());
6810
6811 // Twisted Faith - Mind Flay part
6813 // Increase Mind Flay damage if Shadow Word: Pain present on target
6815 AddPct(DoneTotalMod, aurEff->GetAmount());
6816 }
6817 // Smite
6818 else if (spellProto->SpellFamilyFlags[0] & 0x80)
6819 {
6820 // Glyph of Smite
6821 if (AuraEffect* aurEff = GetAuraEffect(55692, 0))
6822 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, GetGUID()))
6823 AddPct(DoneTotalMod, aurEff->GetAmount());
6824 }
6825 // Shadow Word: Death
6826 else if (spellProto->SpellFamilyFlags[1] & 0x2)
6827 {
6828 // Glyph of Shadow Word: Death
6829 if (AuraEffect* aurEff = GetAuraEffect(55682, 1))
6831 AddPct(DoneTotalMod, aurEff->GetAmount());
6832 }
6833 break;
6835 // Judgement of Vengeance/Judgement of Corruption
6836 if ((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID == 2292)
6837 {
6838 // Get stack of Holy Vengeance/Blood Corruption on the target added by caster
6839 uint32 stacks = 0;
6841 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6842 {
6843 if (((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID() == GetGUID())
6844 {
6845 stacks = (*itr)->GetBase()->GetStackAmount();
6846 break;
6847 }
6848 }
6849 // + 10% for each application of Holy Vengeance/Blood Corruption on the target
6850 if (stacks)
6851 AddPct(DoneTotalMod, 10 * stacks);
6852 }
6853 break;
6854 case SPELLFAMILY_DRUID:
6855 // Thorns
6856 if (spellProto->SpellFamilyFlags[0] & 0x100)
6857 {
6858 // Brambles
6859 if (AuraEffect* aurEff = GetAuraEffectOfRankedSpell(16836, 0))
6860 AddPct(DoneTotalMod, aurEff->GetAmount());
6861 }
6862 break;
6864 // Fire and Brimstone
6865 if (spellProto->SpellFamilyFlags[1] & 0x00020040)
6866 {
6867 if (victim->HasAuraState(AURA_STATE_CONFLAGRATE, nullptr, this))
6868 {
6869 if (AuraEffect const* aurEFf = GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3173, EFFECT_0))
6870 AddPct(DoneTotalMod, aurEFf->GetAmount());
6871 }
6872 }
6873 // Shadow Bite (15% increase from each dot)
6874 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
6875 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
6876 AddPct(DoneTotalMod, 15 * count);
6877
6878 // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage
6879 if (spellProto->SpellFamilyFlags[0] & 0x00004000 && !victim->HealthAbovePct(25))
6880 DoneTotalMod *= 4;
6881
6882 // Don't let Conflagrate double dip from damage done bonuses (from Immolate/Shadowflame and then for itself)
6883 if (spellProto->SpellFamilyFlags[1] & 0x800000)
6884 DoneTotalMod = 1.0f;
6885 break;
6886 case SPELLFAMILY_HUNTER:
6887 // Steady Shot
6888 if (spellProto->SpellFamilyFlags[1] & 0x1)
6889 if (AuraEffect* aurEff = GetAuraEffect(56826, 0)) // Glyph of Steady Shot
6890 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, 0x00004000, 0, 0, GetGUID()))
6891 AddPct(DoneTotalMod, aurEff->GetAmount());
6892 break;
6894 // Improved Icy Touch
6895 if (spellProto->SpellFamilyFlags[0] & 0x2)
6897 AddPct(DoneTotalMod, aurEff->GetAmount());
6898
6899 // Glacier Rot
6900 if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
6902 if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
6903 AddPct(DoneTotalMod, aurEff->GetAmount());
6904 break;
6905 }
6906
6907 return DoneTotalMod;
6908}
6909
6910uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype) const
6911{
6912 if (!spellProto || damagetype == DIRECT_DAMAGE)
6913 return pdamage;
6914
6915 float TakenTotalMod = 1.0f;
6916
6917 // Mod damage from spell mechanic
6918 if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
6919 {
6920 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
6921 {
6922 if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
6923 return true;
6924 return false;
6925 });
6926 }
6927
6928 //.. taken pct: dummy auras
6930 for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
6931 {
6932 switch ((*i)->GetSpellInfo()->SpellIconID)
6933 {
6934 // Cheat Death
6935 case 2109:
6936 if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
6937 {
6938 // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap
6939 // is 22.5% critical strike damage reduction, or 444 resilience.
6940 // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%)
6941 float mod = -1.0f * GetMeleeCritDamageReduction(400);
6942 AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
6943 }
6944 break;
6945 }
6946 }
6947
6948 // Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
6949 if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
6950 {
6951 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
6952 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
6954
6955 // From caster spells
6956 if (caster)
6957 {
6958 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6959 {
6960 if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto))
6961 return true;
6962 return false;
6963 });
6964 }
6965 }
6966
6967 // Sanctified Wrath (bypass damage reduction)
6968 if (caster && TakenTotalMod < 1.0f)
6969 {
6970 float damageReduction = 1.0f - TakenTotalMod;
6972 for (AuraEffect const* aurEff : casterIgnoreResist)
6973 {
6974 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
6975 continue;
6976
6977 AddPct(damageReduction, -aurEff->GetAmount());
6978 }
6979
6980 TakenTotalMod = 1.0f - damageReduction;
6981 }
6982
6983 float tmpDamage = pdamage * TakenTotalMod;
6984 return uint32(std::max(tmpDamage, 0.0f));
6985}
6986
6988{
6989 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
6990
6991 if (GetTypeId() == TYPEID_PLAYER)
6992 {
6993 // Base value
6994 DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
6995
6996 // Damage bonus from stats
6998 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
6999 {
7000 if ((aurEff->GetMiscValue() & schoolMask) != 0)
7001 {
7002 // stat used stored in miscValueB for this aura
7003 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
7004 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
7005 }
7006 }
7007
7008 // ... and attack power
7010 }
7011
7012 return DoneAdvertisedBenefit;
7013}
7014
7015float Unit::SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/, bool isPeriodic /*= false*/) const
7016{
7018 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
7019 return 0.0f;
7020
7021 // not critting spell
7022 if (!isPeriodic && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7023 return 0.0f;
7024
7025 float crit_chance = 0.0f;
7026 switch (spellInfo->DmgClass)
7027 {
7030 {
7031 auto getPhysicalCritChance = [&]
7032 {
7034 };
7035
7036 auto getMagicCritChance = [&]
7037 {
7038 if (IsPlayer())
7040
7042 };
7043
7044 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
7045 crit_chance = std::max(crit_chance, getPhysicalCritChance());
7046
7047 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
7048 crit_chance = std::max(crit_chance, getMagicCritChance());
7049 break;
7050 }
7053 {
7054 crit_chance += GetUnitCriticalChanceDone(attackType);
7056 break;
7057 }
7058 default:
7059 return 0.0f;
7060 }
7061 // percent done
7062 // only players use intelligence for critical chance computations
7063 if (Player* modOwner = GetSpellModOwner())
7064 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
7065
7066 return std::max(crit_chance, 0.0f);
7067}
7068
7069float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/, bool isPeriodic /*= false*/) const
7070{
7071 // not critting spell
7072 if (!isPeriodic && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7073 return 0.0f;
7074
7075 float crit_chance = doneChance;
7076 switch (spellInfo->DmgClass)
7077 {
7079 {
7080 // taken
7081 if (!spellInfo->IsPositive())
7082 {
7083 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7085
7086 if (caster && caster->CanApplyResilience())
7087 Unit::ApplyResilience(this, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL);
7088
7089 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7090 // applied after resilience
7092 }
7093
7094 // scripted (increase crit chance ... against ... target by x%
7095 if (caster)
7096 {
7097 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7098 for (AuraEffect const* aurEff : mOverrideClassScript)
7099 {
7100 if (!aurEff->IsAffectingSpell(spellInfo))
7101 continue;
7102
7103 float modChance = 0.f;
7104 switch (aurEff->GetMiscValue())
7105 {
7106 case 911: // Shatter (Rank 3)
7107 modChance += 16.f;
7108 [[fallthrough]];
7109 case 910: // Shatter (Rank 2)
7110 modChance += 17.f;
7111 [[fallthrough]];
7112 case 849: // Shatter (Rank 1)
7113 modChance += 17.f;
7114 if (!HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7115 break;
7116
7117 crit_chance += modChance;
7118 break;
7119 case 7917: // Glyph of Shadowburn
7120 if (HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, caster))
7121 crit_chance += aurEff->GetAmount();
7122 break;
7123 case 7997: // Renewed Hope
7124 case 7998:
7125 if (HasAura(6788))
7126 crit_chance += aurEff->GetAmount();
7127 break;
7128 default:
7129 break;
7130 }
7131 }
7132 // Custom crit by class
7133 switch (spellInfo->SpellFamilyName)
7134 {
7135 case SPELLFAMILY_MAGE:
7136 // Glyph of Fire Blast
7137 if (spellInfo->SpellFamilyFlags[0] == 0x2 && spellInfo->SpellIconID == 12)
7139 if (AuraEffect const* aurEff = caster->GetAuraEffect(56369, EFFECT_0))
7140 crit_chance += aurEff->GetAmount();
7141 break;
7142 case SPELLFAMILY_DRUID:
7143 // Improved Faerie Fire
7145 if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
7146 crit_chance += aurEff->GetAmount();
7147
7148 // cumulative effect - don't break
7149
7150 // Starfire
7151 if (spellInfo->SpellFamilyFlags[0] & 0x4 && spellInfo->SpellIconID == 1485)
7152 {
7153 // Improved Insect Swarm
7154 if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
7156 crit_chance += aurEff->GetAmount();
7157 break;
7158 }
7159 break;
7160 case SPELLFAMILY_ROGUE:
7161 // Shiv-applied poisons can't crit
7162 if (caster->FindCurrentSpellBySpellId(5938))
7163 crit_chance = 0.0f;
7164 break;
7166 // Flash of light
7167 if (spellInfo->SpellFamilyFlags[0] & 0x40000000)
7168 {
7169 // Sacred Shield
7170 if (AuraEffect const* aura = GetAuraEffect(58597, 1, GetGUID()))
7171 crit_chance += aura->GetAmount();
7172 break;
7173 }
7174 // Exorcism
7175 else if (spellInfo->GetCategory() == 19)
7176 {
7178 return 100.0f;
7179 break;
7180 }
7181 break;
7182 case SPELLFAMILY_SHAMAN:
7183 // Lava Burst
7184 if (spellInfo->SpellFamilyFlags[1] & 0x00001000)
7185 {
7186 if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, caster->GetGUID()))
7188 return 100.0f;
7189 break;
7190 }
7191 break;
7192 }
7193
7194 // Spell crit suppression
7195 if (GetTypeId() == TYPEID_UNIT)
7196 {
7197 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7198 crit_chance -= levelDiff * 0.7f;
7199 }
7200 }
7201 break;
7202 }
7204 {
7205 // Custom crit by class
7206 if (caster)
7207 {
7208 switch (spellInfo->SpellFamilyName)
7209 {
7210 case SPELLFAMILY_DRUID:
7211 // Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets
7212 if (spellInfo->SpellFamilyFlags[0] & 0x00800000
7213 && spellInfo->SpellIconID == 1680
7215 {
7216 if (AuraEffect const* rendAndTear = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
7217 crit_chance += rendAndTear->GetAmount();
7218 break;
7219 }
7220 break;
7222 // Victory Rush
7223 if (spellInfo->SpellFamilyFlags[1] & 0x100)
7224 {
7225 // Glyph of Victory Rush
7226 if (AuraEffect const* aurEff = caster->GetAuraEffect(58382, 0))
7227 crit_chance += aurEff->GetAmount();
7228 break;
7229 }
7230 break;
7231 }
7232 }
7233 [[fallthrough]]; // Calculate critical strike chance for both Ranged and Melee spells
7234 }
7236 if (caster)
7237 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7238 break;
7240 default:
7241 return 0.f;
7242 }
7243
7244 if (caster)
7245 {
7246 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7247 {
7248 if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo))
7249 return true;
7250 return false;
7251 });
7252 }
7253
7254 return std::max(crit_chance, 0.0f);
7255}
7256
7257/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7258{
7259 // Calculate critical bonus
7260 int32 crit_bonus = damage;
7261 float crit_mod = 0.0f;
7262
7263 switch (spellProto->DmgClass)
7264 {
7265 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
7268 crit_bonus += damage;
7269 break;
7270 default:
7271 crit_bonus += damage / 2; // for spells is 50%
7272 break;
7273 }
7274
7275 if (caster)
7276 {
7277 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7278
7279 if (victim)
7281
7282 if (crit_bonus != 0)
7283 AddPct(crit_bonus, crit_mod);
7284
7285 crit_bonus -= damage;
7286
7287 if (damage > uint32(crit_bonus))
7288 {
7289 // adds additional damage to critBonus (from talents)
7290 if (Player* modOwner = caster->GetSpellModOwner())
7291 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
7292 }
7293
7294 crit_bonus += damage;
7295 }
7296
7297 return crit_bonus;
7298}
7299
7300/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7301{
7302 // Calculate critical bonus
7303 int32 crit_bonus;
7304 switch (spellProto->DmgClass)
7305 {
7306 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
7309 crit_bonus = damage;
7310 break;
7311 default:
7312 crit_bonus = damage / 2; // for spells is 50%
7313 break;
7314 }
7315
7316 if (caster)
7317 {
7318 if (victim)
7319 {
7320 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
7321 crit_bonus = int32(crit_bonus * caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
7322 }
7323 }
7324
7325 if (crit_bonus > 0)
7326 damage += crit_bonus;
7327
7328 if (caster)
7329 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7330
7331 return damage;
7332}
7333
7334uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
7335{
7336 // For totems get healing bonus from owner (statue isn't totem in fact)
7337 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7338 if (Unit* owner = GetOwner())
7339 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, donePctTotal, stack);
7340
7341 // No bonus healing for potion spells
7342 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7343 return healamount;
7344
7345 float ApCoeffMod = 1.0f;
7346 int32 DoneTotal = 0;
7347 float DoneTotalMod = donePctTotal ? *donePctTotal : SpellHealingPctDone(victim, spellProto);
7348
7349 // done scripted mod (take it from owner)
7350 Unit const* owner = GetOwner() ? GetOwner() : this;
7351 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7352 for (AuraEffect const* aurEff : mOverrideClassScript)
7353 {
7354 if (!aurEff->IsAffectingSpell(spellProto))
7355 continue;
7356
7357 switch (aurEff->GetMiscValue())
7358 {
7359 case 4415: // Increased Rejuvenation Healing
7360 case 4953:
7361 case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
7362 DoneTotal += aurEff->GetAmount();
7363 break;
7364 default:
7365 break;
7366 }
7367 }
7368
7369 // Custom scripted damage
7370 switch (spellProto->SpellFamilyName)
7371 {
7373 // Impurity (dummy effect)
7374 if (GetTypeId() == TYPEID_PLAYER)
7375 {
7376 PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
7377 for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
7378 {
7379 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
7380 continue;
7381
7382 switch (itr->first)
7383 {
7384 case 49220:
7385 case 49633:
7386 case 49635:
7387 case 49636:
7388 case 49638:
7389 if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
7390 AddPct(ApCoeffMod, proto->GetEffect(EFFECT_0).CalcValue());
7391 break;
7392 }
7393 }
7394 }
7395 break;
7396 }
7397
7398 // Done fixed damage bonus auras
7399 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7400 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7401 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7402
7403 // Pets just add their bonus damage to their spell damage
7404 // note that their spell damage is just gain of their own auras
7406 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7407
7408 // Check for table values
7409 float coeff = spellEffectInfo.BonusCoefficient;
7410 if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
7411 {
7412 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
7414 APbonus += GetTotalAttackPowerValue(attType);
7415
7416 if (damagetype == DOT)
7417 {
7418 coeff = bonus->dot_damage;
7419 if (bonus->ap_dot_bonus > 0)
7420 DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
7421 }
7422 else
7423 {
7424 coeff = bonus->direct_damage;
7425 if (bonus->ap_bonus > 0)
7426 DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
7427 }
7428 }
7429 else
7430 {
7431 // No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default
7432 if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
7433 return uint32(std::max(healamount * DoneTotalMod, 0.0f));
7434 }
7435
7436 // Default calculation
7437 if (DoneAdvertisedBenefit)
7438 {
7439 if (coeff < 0.f)
7440 coeff = CalculateDefaultCoefficient(spellProto, damagetype) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
7441
7442 float factorMod = CalculateSpellpowerCoefficientLevelPenalty(spellProto) * stack;
7443 if (Player* modOwner = GetSpellModOwner())
7444 {
7445 coeff *= 100.0f;
7446 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
7447 coeff /= 100.0f;
7448 }
7449
7450 DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
7451 }
7452
7453 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7454 {
7455 switch (otherSpellEffect.ApplyAuraName)
7456 {
7457 // Bonus healing does not apply to these spells
7460 DoneTotal = 0;
7461 break;
7462 default:
7463 break;
7464 }
7465 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7466 DoneTotal = 0;
7467 }
7468
7469 float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod;
7470
7471 // apply spellmod to Done amount
7472 if (Player* modOwner = GetSpellModOwner())
7473 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
7474
7475 return uint32(std::max(heal, 0.0f));
7476}
7477
7478float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7479{
7480 // For totems get healing bonus from owner
7481 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7482 if (Unit* owner = GetOwner())
7483 return owner->SpellHealingPctDone(victim, spellProto);
7484
7485 // Some spells don't benefit from done mods
7486 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
7487 return 1.0f;
7488
7489 // Some spells don't benefit from done mods
7491 return 1.0f;
7492
7493 // No bonus healing for potion spells
7494 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7495 return 1.0f;
7496
7497 float DoneTotalMod = 1.0f;
7498
7499 // Healing done percent
7501
7502 // done scripted mod (take it from owner)
7503 Unit const* owner = GetOwner() ? GetOwner() : this;
7504 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7505 for (AuraEffect const* aurEff : mOverrideClassScript)
7506 {
7507 if (!aurEff->IsAffectingSpell(spellProto))
7508 continue;
7509
7510 switch (aurEff->GetMiscValue())
7511 {
7512 case 21: // Test of Faith
7513 case 6935:
7514 case 6918:
7515 if (victim->HealthBelowPct(50))
7516 AddPct(DoneTotalMod, aurEff->GetAmount());
7517 break;
7518 case 7798: // Glyph of Regrowth
7519 {
7521 AddPct(DoneTotalMod, aurEff->GetAmount());
7522 break;
7523 }
7524 case 8477: // Nourish Heal Boost
7525 {
7526 int32 stepPercent = aurEff->GetAmount();
7527 int32 modPercent = 0;
7528 AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
7529 for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
7530 {
7531 Aura const* aura = itr->second->GetBase();
7532 if (aura->GetCasterGUID() != GetGUID())
7533 continue;
7534
7535 SpellInfo const* m_spell = aura->GetSpellInfo();
7536 if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
7537 !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
7538 continue;
7539 modPercent += stepPercent * aura->GetStackAmount();
7540 }
7541 AddPct(DoneTotalMod, modPercent);
7542 break;
7543 }
7544 case 7871: // Glyph of Lesser Healing Wave
7545 {
7546 if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0))
7547 AddPct(DoneTotalMod, aurEff->GetAmount());
7548 break;
7549 }
7550 default:
7551 break;
7552 }
7553 }
7554
7555 return DoneTotalMod;
7556}
7557
7558uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype) const
7559{
7560 float TakenTotalMod = 1.0f;
7561
7562 // Healing taken percent
7564 if (minval)
7565 AddPct(TakenTotalMod, minval);
7566
7568 if (maxval)
7569 AddPct(TakenTotalMod, maxval);
7570
7571 // Nourish cast
7572 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7573 {
7574 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7576 // increase healing by 20%
7577 TakenTotalMod *= 1.2f;
7578 }
7579
7580 if (damagetype == DOT)
7581 {
7582 // Healing over time taken percent
7583 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7584 if (minval_hot)
7585 AddPct(TakenTotalMod, minval_hot);
7586
7587 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7588 if (maxval_hot)
7589 AddPct(TakenTotalMod, maxval_hot);
7590 }
7591
7592 if (caster)
7593 {
7594 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff) -> bool
7595 {
7596 if (caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectingSpell(spellProto))
7597 return true;
7598 return false;
7599 });
7600 }
7601
7602 float heal = healamount * TakenTotalMod;
7603 return uint32(std::max(heal, 0.0f));
7604}
7605
7607{
7608 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7609 {
7610 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7611 return true;
7612 return false;
7613 });
7614
7615 // Healing bonus of spirit, intellect and strength
7616 if (GetTypeId() == TYPEID_PLAYER)
7617 {
7618 // Base value
7619 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7620
7621 // Healing bonus from stats
7623 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7624 {
7625 // stat used dependent from misc value (stat index)
7626 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7627 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7628 }
7629
7630 // ... and attack power
7632 for (AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i)
7633 if ((*i)->GetMiscValue() & schoolMask)
7634 advertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
7635 }
7636 return advertisedBenefit;
7637}
7638
7640{
7641 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7642 return false;
7643
7644 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7645 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7646 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7647 return true;
7648
7649 // If m_immuneToDamage type contain magic, IMMUNE damage.
7650 uint32 damageImmunityMask = GetDamageImmunityMask();
7651 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7652 return true;
7653
7654 return false;
7655}
7656
7657bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
7658{
7659 if (!spellInfo)
7660 return false;
7661
7662 // for example 40175
7664 return false;
7665
7667 return false;
7668
7669 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7670 {
7671 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7672 uint32 schoolImmunityMask = 0;
7674 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7675 if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
7676 schoolImmunityMask |= itr->first;
7677
7678 // // We need to be immune to all types
7679 if ((schoolImmunityMask & schoolMask) == schoolMask)
7680 return true;
7681
7682 // If m_immuneToDamage type contain magic, IMMUNE damage.
7683 uint32 damageImmunityMask = GetDamageImmunityMask();
7684 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7685 return true;
7686 }
7687
7688 return false;
7689}
7690
7691bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7692{
7693 if (!spellInfo)
7694 return false;
7695
7696 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7697 {
7699 if (!requireImmunityPurgesEffectAttribute)
7700 return range.begin() != range.end();
7701
7702 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7703 {
7704 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second))
7705 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7706 return true;
7707
7708 return false;
7709 });
7710 };
7711
7712 // Single spell immunity.
7714 if (hasImmunity(idList, spellInfo->Id))
7715 return true;
7716
7718 return false;
7719
7720 if (uint32 dispel = spellInfo->Dispel)
7721 {
7723 if (hasImmunity(dispelList, dispel))
7724 return true;
7725 }
7726
7727 // Spells that don't have effectMechanics.
7728 if (uint32 mechanic = spellInfo->Mechanic)
7729 {
7731 if (hasImmunity(mechanicList, mechanic))
7732 return true;
7733 }
7734
7735 bool immuneToAllEffects = true;
7736 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7737 {
7738 // State/effect immunities applied by aura expect full spell immunity
7739 // Ignore effects with mechanic, they are supposed to be checked separately
7740 if (!spellEffectInfo.IsEffect())
7741 continue;
7742
7743 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7744 {
7745 immuneToAllEffects = false;
7746 break;
7747 }
7748 }
7749
7750 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7751 return true;
7752
7753 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7754 {
7755 uint32 schoolImmunityMask = 0;
7757 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7758 {
7759 if ((itr->first & schoolMask) == 0)
7760 continue;
7761
7762 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
7763 if (requireImmunityPurgesEffectAttribute)
7764 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7765 continue;
7766
7767 // Consider the school immune if any of these conditions are not satisfied.
7768 // In case of no immuneSpellInfo, ignore that condition and check only the other conditions
7769 if ((immuneSpellInfo && !immuneSpellInfo->IsPositive()) || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
7770 if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7771 schoolImmunityMask |= itr->first;
7772 }
7773
7774 if ((schoolImmunityMask & schoolMask) == schoolMask)
7775 return true;
7776 }
7777
7778 return false;
7779}
7780
7782{
7783 uint32 mask = 0;
7785 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7786 mask |= itr->first;
7787
7788 return mask;
7789}
7790
7792{
7793 uint32 mask = 0;
7795 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7796 mask |= itr->first;
7797
7798 return mask;
7799}
7800
7802{
7803 uint32 mask = 0;
7805 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7806 mask |= (1 << itr->first);
7807
7808 return mask;
7809}
7810
7811bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
7812 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7813{
7814 if (!spellInfo || !spellEffectInfo.IsEffect())
7815 return false;
7816
7818 return false;
7819
7820 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7821 {
7823 if (!requireImmunityPurgesEffectAttribute)
7824 return range.begin() != range.end();
7825
7826 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7827 {
7828 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second))
7829 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7830 return true;
7831
7832 return false;
7833 });
7834 };
7835
7836 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7838 if (hasImmunity(effectList, spellEffectInfo.Effect))
7839 return true;
7840
7841 if (uint32 mechanic = spellEffectInfo.Mechanic)
7842 {
7844 if (hasImmunity(mechanicList, mechanic))
7845 return true;
7846 }
7847
7848 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7849 {
7851 {
7853 if (hasImmunity(list, aura))
7854 return true;
7855 }
7856
7858 {
7859 // Check for immune to application of harmful magical effects
7861 for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
7862 if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
7863 ((caster && !IsFriendlyTo(caster)) || !spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex))) // Harmful
7864 return true;
7865 }
7866 }
7867
7868 return false;
7869}
7870
7871uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
7872{
7873 if (!victim || pdamage == 0)
7874 return 0;
7875
7876 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
7877
7878 // Done fixed damage bonus auras
7879 int32 DoneFlatBenefit = 0;
7880
7881 // ..done
7882 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
7883
7884 // ..done
7885 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
7886
7887 // ..done (base at attack power for marked target and base at attack power for creature type)
7888 int32 APbonus = 0;
7889
7890 if (attType == RANGED_ATTACK)
7891 {
7893
7894 // ..done (base at attack power and creature type)
7896 }
7897 else
7898 {
7900
7901 // ..done (base at attack power and creature type)
7903 }
7904
7905 if (APbonus != 0) // Can be negative
7906 {
7907 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
7908 DoneFlatBenefit += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized));
7909 }
7910
7911 // Done total percent damage auras
7912 float DoneTotalMod = 1.0f;
7913
7914 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
7915
7916 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
7917 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
7918 {
7919 // Some spells don't benefit from pct done mods
7920 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS))
7921 {
7922 float maxModDamagePercentSchool = 0.0f;
7923 if (GetTypeId() == TYPEID_PLAYER)
7924 {
7925 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
7926 if (schoolMask & (1 << i))
7927 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
7928 }
7929 else
7930 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
7931
7932 DoneTotalMod *= maxModDamagePercentSchool;
7933 }
7934 }
7935
7937
7938 // bonus against aurastate
7939 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7940 {
7941 if (victim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
7942 return true;
7943 return false;
7944 });
7945
7946 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
7947 if (spellProto && spellProto->Mechanic)
7949
7950 // done scripted mod (take it from owner)
7951 Unit* owner = GetOwner() ? GetOwner() : this;
7952 AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7953 for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
7954 {
7955 if (!(*i)->IsAffectingSpell(spellProto))
7956 continue;
7957
7958 switch ((*i)->GetMiscValue())
7959 {
7960 // Tundra Stalker
7961 // Merciless Combat
7962 case 7277:
7963 {
7964 // Merciless Combat
7965 if ((*i)->GetSpellInfo()->SpellIconID == 2656)
7966 {
7967 if (!victim->HealthAbovePct(35))
7968 AddPct(DoneTotalMod, (*i)->GetAmount());
7969 }
7970 // Tundra Stalker
7971 else
7972 {
7973 // Frost Fever (target debuff)
7974 if (victim->HasAura(55095))
7975 AddPct(DoneTotalMod, (*i)->GetAmount());
7976 }
7977 break;
7978 }
7979 // Rage of Rivendare
7980 case 7293:
7981 {
7983 AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f);
7984 break;
7985 }
7986 // Marked for Death
7987 case 7598:
7988 case 7599:
7989 case 7600:
7990 case 7601:
7991 case 7602:
7992 {
7993 if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
7994 AddPct(DoneTotalMod, (*i)->GetAmount());
7995 break;
7996 }
7997 // Dirty Deeds
7998 case 6427:
7999 case 6428:
8000 {
8001 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
8002 {
8003 // effect 0 has expected value but in negative state
8004 int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
8005 AddPct(DoneTotalMod, bonus);
8006 }
8007 break;
8008 }
8009 }
8010 }
8011
8012 // Custom scripted damage
8013 if (spellProto)
8014 {
8015 switch (spellProto->SpellFamilyName)
8016 {
8018 // Glacier Rot
8019 if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
8021 if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
8022 AddPct(DoneTotalMod, aurEff->GetAmount());
8023 break;
8024 }
8025 }
8026
8027 float tmpDamage = float(int32(pdamage) + DoneFlatBenefit) * DoneTotalMod;
8028
8029 // bonus result can be negative
8030 return uint32(std::max(tmpDamage, 0.0f));
8031}
8032
8033uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
8034{
8035 if (pdamage == 0)
8036 return 0;
8037
8038 int32 TakenFlatBenefit = 0;
8039
8040 // ..taken
8042
8043 if (attType != RANGED_ATTACK)
8045 else
8047
8048 if ((TakenFlatBenefit < 0) && (pdamage < static_cast<uint32>(-TakenFlatBenefit)))
8049 return 0;
8050
8051 // Taken total percent damage auras
8052 float TakenTotalMod = 1.0f;
8053
8054 // ..taken
8056
8057 // .. taken pct (special attacks)
8058 if (spellProto)
8059 {
8060 // From caster spells
8061 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8062 {
8063 if (aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto))
8064 return true;
8065 return false;
8066 });
8067
8068 // Mod damage from spell mechanic
8069 uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask();
8070
8071 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
8072 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
8073 mechanicMask |= (1 << MECHANIC_BLEED);
8074
8075 if (mechanicMask)
8076 {
8077 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
8078 {
8079 if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
8080 return true;
8081 return false;
8082 });
8083 }
8084 }
8085
8086 // .. taken pct: dummy auras
8088 for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
8089 {
8090 switch ((*i)->GetSpellInfo()->SpellIconID)
8091 {
8092 // Cheat Death
8093 case 2109:
8094 if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
8095 {
8096 // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap
8097 // is 22.5% critical strike damage reduction, or 444 resilience.
8098 // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%)
8099 float mod = -1.0f * GetMeleeCritDamageReduction(400);
8100 AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
8101 }
8102 break;
8103 }
8104 }
8105
8106 // .. taken pct: class scripts
8107 //*AuraEffectList const& mclassScritAuras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8108 //for (AuraEffectList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
8109 //{
8110 // switch ((*i)->GetMiscValue())
8111 // {
8112 // }
8113 //}*/
8114
8115 if (attType != RANGED_ATTACK)
8117 else
8119
8120 // Sanctified Wrath (bypass damage reduction)
8121 if (TakenTotalMod < 1.0f)
8122 {
8123 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8124
8125 float damageReduction = 1.0f - TakenTotalMod;
8127 for (AuraEffect const* aurEff : casterIgnoreResist)
8128 {
8129 if (!(aurEff->GetMiscValue() & attackSchoolMask))
8130 continue;
8131
8132 AddPct(damageReduction, -aurEff->GetAmount());
8133 }
8134
8135 TakenTotalMod = 1.0f - damageReduction;
8136 }
8137
8138 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
8139 return uint32(std::max(tmpDamage, 0.0f));
8140}
8141
8142void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
8143{
8144 if (apply)
8145 m_spellImmune[op].emplace(type, spellId);
8146 else
8147 {
8148 auto bounds = m_spellImmune[op].equal_range(type);
8149 for (auto itr = bounds.first; itr != bounds.second;)
8150 {
8151 if (itr->second == spellId)
8152 itr = m_spellImmune[op].erase(itr);
8153 else
8154 ++itr;
8155 }
8156 }
8157}
8158
8160{
8161 // normalized proc chance for weapon attack speed
8162 // (odd formula...)
8164 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8166 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8167 return 0;
8168}
8169
8170float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
8171{
8172 // proc per minute chance calculation
8173 if (PPM <= 0)
8174 return 0.0f;
8175
8176 // Apply chance modifer aura
8177 if (spellProto)
8178 if (Player* modOwner = GetSpellModOwner())
8179 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
8180
8181 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8182}
8183
8184void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
8185{
8186 if (mount)
8187 SetMountDisplayId(mount);
8188
8190
8191 if (Player* player = ToPlayer())
8192 {
8193 // mount as a vehicle
8194 if (VehicleId)
8195 {
8196 if (CreateVehicleKit(VehicleId, creatureEntry))
8197 {
8198 // Send others that we now have a vehicle
8200 data << GetPackGUID();
8201 data << uint32(VehicleId);
8202 SendMessageToSet(&data, true);
8203
8204 player->SendOnCancelExpectedVehicleRideAura();
8205
8206 // mounts can also have accessories
8208 }
8209 }
8210
8211 // unsummon pet
8212 Pet* pet = player->GetPet();
8213 if (pet)
8214 {
8216 // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface
8217 if (bg && bg->isArena())
8219 else
8220 player->UnsummonPetTemporaryIfAny();
8221 }
8222
8223 // if we have charmed npc, stun him also (everywhere)
8224 if (Unit* charm = player->GetCharmed())
8225 if (charm->GetTypeId() == TYPEID_UNIT)
8226 charm->SetUnitFlag(UNIT_FLAG_STUNNED);
8227
8228 player->SendMovementSetCollisionHeight(player->GetCollisionHeight());
8229 }
8230
8232}
8233
8235{
8236 if (!IsMounted())
8237 return;
8238
8241
8242 if (Player* thisPlayer = ToPlayer())
8243 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight());
8244
8245 WorldPacket data(SMSG_DISMOUNT, 8);
8246 data << GetPackGUID();
8247 SendMessageToSet(&data, true);
8248
8249 // dismount as a vehicle
8251 {
8252 // Send other players that we are no longer a vehicle
8254 data << GetPackGUID();
8255 data << uint32(0);
8256 ToPlayer()->SendMessageToSet(&data, true);
8257 // Remove vehicle from player
8259 }
8260
8262
8263 // only resummon old pet if the player is already added to a map
8264 // this prevents adding a pet to a not created map which would otherwise cause a crash
8265 // (it could probably happen when logging in after a previous crash)
8266 if (Player* player = ToPlayer())
8267 {
8268 if (Pet* pPet = player->GetPet())
8269 {
8270 if (pPet->HasUnitFlag(UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED))
8271 pPet->RemoveUnitFlag(UNIT_FLAG_STUNNED);
8272 }
8273 else
8274 player->ResummonPetTemporaryUnSummonedIfAny();
8275
8276 // if we have charmed npc, remove stun also
8277 if (Unit* charm = player->GetCharmed())
8278 if (charm->GetTypeId() == TYPEID_UNIT && charm->HasUnitFlag(UNIT_FLAG_STUNNED) && !charm->HasUnitState(UNIT_STATE_STUNNED))
8279 charm->RemoveUnitFlag(UNIT_FLAG_STUNNED);
8280 }
8281}
8282
8291
8293{
8294 if (!enemy)
8295 return;
8296
8297 if (CanHaveThreatList())
8298 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8299 else
8300 SetInCombatWith(enemy);
8301}
8302
8303void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8304{
8305 if (apply)
8306 {
8309 if (!keepCombat)
8311 }
8312 else
8314}
8315
8316void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8317{
8318 if (apply)
8319 {
8322 if (!keepCombat)
8323 {
8324 std::list<CombatReference*> toEnd;
8325 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8326 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8327 toEnd.push_back(pair.second);
8328 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8329 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8330 toEnd.push_back(pair.second);
8331 for (CombatReference* ref : toEnd)
8332 ref->EndCombat();
8333 }
8334 }
8335 else
8337}
8338
8339void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8340{
8341 if (apply)
8342 {
8345 if (!keepCombat)
8346 {
8347 std::list<CombatReference*> toEnd;
8348 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8349 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8350 toEnd.push_back(pair.second);
8351 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8352 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8353 toEnd.push_back(pair.second);
8354 for (CombatReference* ref : toEnd)
8355 ref->EndCombat();
8356 }
8357 }
8358 else
8360}
8361
8363{
8365}
8366
8367bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8368{
8369 if (!IsAlive())
8370 return false;
8371
8373 return false;
8374
8375 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8376 return false;
8377
8378 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8379}
8380
8382{
8383 int32 gain = 0;
8384
8385 if (dVal == 0)
8386 return 0;
8387
8388 int32 curHealth = (int32)GetHealth();
8389
8390 int32 val = dVal + curHealth;
8391 if (val <= 0)
8392 {
8393 SetHealth(0);
8394 return -curHealth;
8395 }
8396
8397 int32 maxHealth = (int32)GetMaxHealth();
8398
8399 if (val < maxHealth)
8400 {
8401 SetHealth(val);
8402 gain = val - curHealth;
8403 }
8404 else if (curHealth != maxHealth)
8405 {
8406 SetHealth(maxHealth);
8407 gain = maxHealth - curHealth;
8408 }
8409
8410 return gain;
8411}
8412
8414{
8415 int32 gain = 0;
8416
8417 if (dVal == 0)
8418 return 0;
8419
8420 int32 curHealth = (int32)GetHealth();
8421
8422 int32 val = dVal + curHealth;
8423 if (val <= 0)
8424 {
8425 return -curHealth;
8426 }
8427
8428 int32 maxHealth = (int32)GetMaxHealth();
8429
8430 if (val < maxHealth)
8431 gain = dVal;
8432 else if (curHealth != maxHealth)
8433 gain = maxHealth - curHealth;
8434
8435 return gain;
8436}
8437
8438// returns negative amount on power reduction
8439int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8440{
8441 int32 gain = 0;
8442
8443 if (dVal == 0)
8444 return 0;
8445
8446 int32 curPower = (int32)GetPower(power);
8447
8448 int32 val = dVal + curPower;
8449 if (val <= GetMinPower(power))
8450 {
8451 SetPower(power, GetMinPower(power), withPowerUpdate);
8452 return -curPower;
8453 }
8454
8455 int32 maxPower = (int32)GetMaxPower(power);
8456
8457 if (val < maxPower)
8458 {
8459 SetPower(power, val, withPowerUpdate);
8460 gain = val - curPower;
8461 }
8462 else if (curPower != maxPower)
8463 {
8464 SetPower(power, maxPower, withPowerUpdate);
8465 gain = maxPower - curPower;
8466 }
8467
8468 return gain;
8469}
8470
8472{
8473 float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att)) / m_modAttackSpeedPct[att];
8474 return (uint32)f_BaseAttackTime;
8475}
8476
8478{
8480 return true;
8481
8482 // Always seen by owner
8484 if (!guid.IsEmpty())
8485 if (seer->GetGUID() == guid)
8486 return true;
8487
8488 if (Player const* seerPlayer = seer->ToPlayer())
8489 if (Unit* owner = GetOwner())
8490 if (Player* ownerPlayer = owner->ToPlayer())
8491 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8492 return true;
8493
8494 return false;
8495}
8496
8498{
8500 return true;
8501
8503 return true;
8504
8505 return false;
8506}
8507
8509{
8511}
8512
8522
8524{
8525 int32 main_speed_mod = 0;
8526 float stack_bonus = 1.0f;
8527 float non_stack_bonus = 1.0f;
8528
8529 switch (mtype)
8530 {
8531 // Only apply debuffs
8532 case MOVE_FLIGHT_BACK:
8533 case MOVE_RUN_BACK:
8534 case MOVE_SWIM_BACK:
8535 break;
8536 case MOVE_WALK:
8537 return;
8538 case MOVE_RUN:
8539 {
8540 if (IsMounted()) // Use on mount auras
8541 {
8545 }
8546 else
8547 {
8551 }
8552 break;
8553 }
8554 case MOVE_SWIM:
8555 {
8557 break;
8558 }
8559 case MOVE_FLIGHT:
8560 {
8561 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8562 {
8565
8566 // for some spells this mod is applied on vehicle owner
8567 int32 owner_speed_mod = 0;
8568
8569 if (Unit* owner = GetCharmer())
8570 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8571
8572 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8573 }
8574 else if (IsMounted())
8575 {
8578 }
8579 else // Use not mount (shapeshift for example) auras (should stack)
8581
8583
8584 // Update speed for vehicle if available
8585 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8587 break;
8588 }
8589 default:
8590 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8591 return;
8592 }
8593
8594 // now we ready for speed calculation
8595 float speed = std::max(non_stack_bonus, stack_bonus);
8596 if (main_speed_mod)
8597 AddPct(speed, main_speed_mod);
8598
8599 switch (mtype)
8600 {
8601 case MOVE_RUN:
8602 case MOVE_SWIM:
8603 case MOVE_FLIGHT:
8604 {
8605 // Set creature speed rate
8606 if (GetTypeId() == TYPEID_UNIT)
8607 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8608
8609 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8612 {
8613 if (Creature* creature = ToCreature())
8614 {
8615 uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
8616 if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
8617 break;
8618 }
8619
8620 // Use speed from aura
8621 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8622 if (speed > max_speed)
8623 speed = max_speed;
8624 }
8625 break;
8626 }
8627 default:
8628 break;
8629 }
8630
8631 if (Creature* creature = ToCreature())
8632 {
8633 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8634 {
8636 {
8637 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8638 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8639 {
8640 float ownerSpeed = followed->GetSpeedRate(mtype);
8641 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8642 speed = ownerSpeed;
8643 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8644 }
8645 }
8646 }
8647 }
8648
8649 // Apply strongest slow aura mod to speed
8651 if (slow)
8652 AddPct(speed, slow);
8653
8654 if (float minSpeedMod = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED))
8655 {
8656 float baseMinSpeed = 1.0f;
8657 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8658 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8659
8660 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8661 if (speed < min_speed)
8662 speed = min_speed;
8663 }
8664
8665 SetSpeedRate(mtype, speed);
8666}
8667
8669{
8670 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8671}
8672
8673void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8674{
8675 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8676}
8677
8678void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8679{
8680 if (rate < 0)
8681 rate = 0.0f;
8682
8683 // Update speed only on change
8685 if (m_speed_rate[mtype] == rate && !HasPendingMovementChange(changeType)) //todo: is the "!HasPendingMovementChange" part necessary here?
8686 return;
8687
8688 float newSpeedFlat = rate * (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8689 if (IsMovedByClient() && IsInWorld())
8690 MovementPacketSender::SendSpeedChangeToMover(this, mtype, newSpeedFlat);
8691 else if (IsMovedByClient() && !IsInWorld()) // (1)
8692 SetSpeedRateReal(mtype, rate);
8693 else // <=> if(!IsMovedByPlayer())
8694 {
8695 SetSpeedRateReal(mtype, rate);
8696 MovementPacketSender::SendSpeedChangeToAll(this, mtype, newSpeedFlat);
8697 }
8698
8699 // explaination of (1):
8700 // If the player is not in the world yet, it won't reply to the packets requiring an ack. And once the player is in the world, next time a movement
8701 // packet which requires an ack is sent to the client (change of speed for example), the client is kicked from the
8702 // server on the ground that it should have replied to the first packet first. That line is a hacky fix
8703 // in the sense that it doesn't work like that in retail since buffs are applied only after the player has been
8704 // initialized in the world. cf description of PR #18771
8705}
8706
8708{
8709 if (!IsInCombat() && ToPlayer())
8710 if (Pet* pet = ToPlayer()->GetPet())
8711 pet->SetSpeedRate(mtype, rate);
8712
8713 m_speed_rate[mtype] = rate;
8715}
8716
8718{
8719 while (!m_followingMe.empty())
8720 (*m_followingMe.begin())->SetTarget(nullptr);
8721}
8722
8724{
8726}
8727
8729{
8730 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
8731 m_deathState = s;
8732
8733 bool isOnVehicle = GetVehicle() != nullptr;
8734
8735 if (s != ALIVE && s != JUST_RESPAWNED)
8736 {
8737 CombatStop();
8738 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
8739
8740 if (IsNonMeleeSpellCast(false))
8742
8743 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
8744 // vehicles use special type of charm that is not removed by the next function
8745 // triggering an assert
8749 }
8750
8751 if (s == JUST_DIED)
8752 {
8753 // remove aurastates allowing special moves
8756
8757 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
8758 if (!isOnVehicle)
8759 {
8760 if (GetMotionMaster()->StopOnDeath())
8761 DisableSpline();
8762 }
8763
8764 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
8765 // do not why since in IncreaseMaxHealth currenthealth is checked
8766 SetHealth(0);
8767 SetPower(GetPowerType(), 0);
8769
8770 // players in instance don't have ZoneScript, but they have InstanceScript
8771 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
8772 zoneScript->OnUnitDeath(this);
8773 }
8774 else if (s == JUST_RESPAWNED)
8775 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
8776}
8777
8778//======================================================================
8779
8784
8790
8791void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
8792{
8793 if (!target->IsEngaged() && !canInitialAggro)
8794 return;
8795 target->EngageWithTarget(this);
8796 if (Unit* targetOwner = target->GetCharmerOrOwner())
8797 targetOwner->EngageWithTarget(this);
8798
8799 //Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped.
8800 if (Creature* creature = target->ToCreature())
8801 if (!creature->hasLootRecipient() && GetTypeId() == TYPEID_PLAYER)
8802 creature->SetLootRecipient(this);
8803
8805 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
8806 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
8807 {
8808 myPlayerOwner->UpdatePvP(true);
8809 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
8811 }
8812}
8813
8815{
8816 ASSERT(!IsPet()); // player pets do not use UNIT_FLAG_PET_IN_COMBAT for this purpose - but player pets should also never have minions of their own to call this
8817
8818 bool state = false;
8819 for (Unit* minion : m_Controlled)
8820 if (minion->IsInCombat())
8821 {
8822 state = true;
8823 break;
8824 }
8825
8826 if (state)
8828 else
8830}
8831
8832//======================================================================
8833
8835{
8836 DiminishingReturn const& diminish = m_Diminishing[group];
8837 if (!diminish.hitCount)
8838 return DIMINISHING_LEVEL_1;
8839
8840 // If last spell was cast more than 15 seconds ago - reset level
8841 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 15000)
8842 return DIMINISHING_LEVEL_1;
8843
8844 return DiminishingLevels(diminish.hitCount);
8845}
8846
8847void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered)
8848{
8849 DiminishingGroup group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
8850 uint32 currentLevel = GetDiminishing(group);
8851 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel(triggered);
8852
8853 DiminishingReturn& diminish = m_Diminishing[group];
8854 if (currentLevel < maxLevel)
8855 diminish.hitCount = currentLevel + 1;
8856}
8857
8858bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
8859{
8860 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
8861 if (duration == -1 || group == DIMINISHING_NONE)
8862 return true;
8863
8864 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration(triggered);
8865
8866 // test pet/charm masters instead pets/charmeds
8867 Unit const* targetOwner = GetCharmerOrOwner();
8868 Unit const* casterOwner = caster->GetCharmerOrOwner();
8869
8870 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
8871 if (limitDuration > 0 && duration > limitDuration)
8872 {
8873 Unit const* target = targetOwner ? targetOwner : this;
8874 WorldObject const* source = casterOwner ? casterOwner : caster;
8875
8876 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
8877 duration = limitDuration;
8878 }
8879
8880 float mod = 1.0f;
8881 if (group == DIMINISHING_TAUNT)
8882 {
8883 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
8884 {
8885 DiminishingLevels diminish = previousLevel;
8886 switch (diminish)
8887 {
8888 case DIMINISHING_LEVEL_1: break;
8889 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
8890 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
8891 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
8892 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
8893 default: break;
8894 }
8895 }
8896 }
8897 // Some diminishings applies to mobs too (for example, Stun)
8898 else if (auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_ALL ||
8899 (auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_PLAYER &&
8900 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
8901 {
8902 DiminishingLevels diminish = previousLevel;
8903 switch (diminish)
8904 {
8905 case DIMINISHING_LEVEL_1: break;
8906 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
8907 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
8908 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
8909 default: break;
8910 }
8911 }
8912
8913 duration = int32(duration * mod);
8914 return (duration != 0);
8915}
8916
8918{
8919 // Checking for existing in the table
8920 DiminishingReturn& diminish = m_Diminishing[group];
8921
8922 if (apply)
8923 ++diminish.stack;
8924 else if (diminish.stack)
8925 {
8926 --diminish.stack;
8927
8928 // Remember time after last aura from group removed
8929 if (!diminish.stack)
8930 diminish.hitTime = GameTime::GetGameTimeMS();
8931 }
8932}
8933
8935{
8936 for (DiminishingReturn& dim : m_Diminishing)
8937 dim.Clear();
8938}
8939
8941{
8942 if (GetTypeId() == TYPEID_PLAYER)
8943 {
8945 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
8946 if (ssEntry && ssEntry->CreatureType > 0)
8947 return ssEntry->CreatureType;
8948 else
8949 {
8950 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
8951 return raceEntry->CreatureType;
8952 }
8953 }
8954 else
8955 return ToCreature()->GetCreatureTemplate()->type;
8956}
8957
8959{
8960 uint32 creatureType = GetCreatureType();
8961 return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0;
8962}
8963
8968
8970{
8972 return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR;
8973}
8974
8976{
8977 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(GetTransformSpell()))
8978 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
8979 return false;
8980
8981 if (ShapeshiftForm form = GetShapeshiftForm())
8982 {
8983 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
8984 if (!shapeshift)
8985 return true;
8986
8987 if (!(shapeshift->Flags & 0x1))
8988 return true;
8989 }
8990
8992 return false;
8993
8994 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(GetDisplayId());
8995 if (!display)
8996 return true;
8997
8999 if (!displayExtra)
9000 return true;
9001
9002 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
9003 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
9004
9005 if (model && !(model->HasFlag(CREATURE_MODEL_DATA_FLAGS_CAN_MOUNT)))
9006 if (race && !(race->HasFlag(CHRRACES_FLAGS_CAN_MOUNT)))
9007 return true;
9008
9009 return false;
9010}
9011
9012/*#######################################
9013######## ########
9014######## STAT SYSTEM ########
9015######## ########
9016#######################################*/
9017
9018void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
9019{
9020 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9021 {
9022 TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!");
9023 return;
9024 }
9025
9026 if (!amount)
9027 return;
9028
9029 switch (modifierType)
9030 {
9031 case BASE_VALUE:
9032 case TOTAL_VALUE:
9033 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9034 break;
9035 default:
9036 break;
9037 }
9038
9039 UpdateUnitMod(unitMod);
9040}
9041
9042void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
9043{
9044 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9045 {
9046 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
9047 return;
9048 }
9049
9050 if (!pct)
9051 return;
9052
9053 switch (modifierType)
9054 {
9055 case BASE_PCT:
9056 case TOTAL_PCT:
9057 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9058 break;
9059 default:
9060 break;
9061 }
9062
9063 UpdateUnitMod(unitMod);
9064}
9065
9066void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9067{
9068 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9069 return;
9070
9071 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9072 UpdateUnitMod(unitMod);
9073}
9074
9075void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9076{
9077 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9078 return;
9079
9080 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9081 UpdateUnitMod(unitMod);
9082}
9083
9085{
9086 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9087 {
9088 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9089 return 0.0f;
9090 }
9091
9092 return m_auraFlatModifiersGroup[unitMod][modifierType];
9093}
9094
9096{
9097 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9098 {
9099 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9100 return 0.0f;
9101 }
9102
9103 return m_auraPctModifiersGroup[unitMod][modifierType];
9104}
9105
9107{
9108 if (!CanModifyStats())
9109 return;
9110
9111 switch (unitMod)
9112 {
9118
9119 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9120 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9121
9122 case UNIT_MOD_MANA:
9123 case UNIT_MOD_RAGE:
9124 case UNIT_MOD_FOCUS:
9125 case UNIT_MOD_ENERGY:
9126 case UNIT_MOD_HAPPINESS:
9127 case UNIT_MOD_RUNE:
9129
9136
9139
9143
9144 default:
9145 break;
9146 }
9147}
9148
9149void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9150{
9151 UnitMods unitMod;
9152 switch (attackType)
9153 {
9154 case BASE_ATTACK:
9155 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9156 break;
9157 case OFF_ATTACK:
9158 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9159 break;
9160 case RANGED_ATTACK:
9161 unitMod = UNIT_MOD_DAMAGE_RANGED;
9162 break;
9163 default:
9164 ABORT();
9165 break;
9166 }
9167
9168 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9169 {
9170 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9171 return false;
9172
9173 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9174 });
9175
9176 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9177}
9178
9184
9186{
9187 float factor;
9188 UnitMods unitMod;
9189 switch (attackType)
9190 {
9191 case BASE_ATTACK:
9192 factor = 1.0f;
9193 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9194 break;
9195 case OFF_ATTACK:
9196 // off hand has 50% penalty
9197 factor = 0.5f;
9198 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9199 break;
9200 case RANGED_ATTACK:
9201 factor = 1.0f;
9202 unitMod = UNIT_MOD_DAMAGE_RANGED;
9203 break;
9204 default:
9205 ABORT();
9206 break;
9207 }
9208
9209 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9210 {
9211 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9212 return false;
9213
9214 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9215 });
9216
9217 if (attackType == OFF_ATTACK)
9218 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
9219
9220 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9221}
9222
9228
9230{
9232
9233 // value = ((base_value * base_pct) + total_value) * total_pct
9234 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateStat(stat);
9235 value *= GetPctModifierValue(unitMod, BASE_PCT);
9236 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9237 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9238
9239 return value;
9240}
9241
9243{
9244 if (unitMod >= UNIT_MOD_END)
9245 {
9246 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9247 return 0.0f;
9248 }
9249
9250 float value = GetFlatModifierValue(unitMod, BASE_VALUE);
9251 value *= GetPctModifierValue(unitMod, BASE_PCT);
9252 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9253 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9254
9255 return value;
9256}
9257
9259{
9261
9262 switch (unitMod)
9263 {
9264 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9265 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9266 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9267 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9268 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9269 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9270
9271 default:
9272 break;
9273 }
9274
9275 return school;
9276}
9277
9279{
9280 Stats stat = STAT_STRENGTH;
9281
9282 switch (unitMod)
9283 {
9284 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9285 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9286 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9287 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9288 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
9289
9290 default:
9291 break;
9292 }
9293
9294 return stat;
9295}
9296
9298{
9299 switch (unitMod)
9300 {
9301 case UNIT_MOD_RAGE: return POWER_RAGE;
9302 case UNIT_MOD_FOCUS: return POWER_FOCUS;
9303 case UNIT_MOD_ENERGY: return POWER_ENERGY;
9305 case UNIT_MOD_RUNE: return POWER_RUNE;
9307 default:
9308 case UNIT_MOD_MANA: return POWER_MANA;
9309 }
9310}
9311
9329
9330float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const
9331{
9332 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9333 return 0.0f;
9334
9335 return m_weaponDamage[attType][type][damageIndex];
9336}
9337
9343
9344void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
9345{
9347
9348 if (!sendUpdate)
9349 return;
9350
9351 if (Player* player = ToPlayer())
9352 {
9353 // group update
9354 if (player->GetGroup())
9355 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9356
9357 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
9358 }
9359}
9360
9362{
9364 val = 0;
9365 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
9366 val = 1;
9367 else
9368 {
9369 uint32 maxHealth = GetMaxHealth();
9370 if (maxHealth < val)
9371 val = maxHealth;
9372 }
9373
9375
9376 // group update
9377 if (Player* player = ToPlayer())
9378 {
9379 if (player->GetGroup())
9380 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9381 }
9382 else if (Pet* pet = ToCreature()->ToPet())
9383 {
9384 if (pet->isControlled())
9385 {
9386 Unit* owner = GetOwner();
9387 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9389 }
9390 }
9391}
9392
9394{
9395 if (!val)
9396 val = 1;
9397
9398 uint32 health = GetHealth();
9400
9401 // group update
9402 if (GetTypeId() == TYPEID_PLAYER)
9403 {
9404 if (ToPlayer()->GetGroup())
9406 }
9407 else if (Pet* pet = ToCreature()->ToPet())
9408 {
9409 if (pet->isControlled())
9410 {
9411 Unit* owner = GetOwner();
9412 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9414 }
9415 }
9416
9417 if (val < health)
9418 SetHealth(val);
9419}
9420
9421void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/, bool force /*= false*/)
9422{
9423 if (!force && GetPower(power) == val)
9424 return;
9425
9426 uint32 maxPower = GetMaxPower(power);
9427 if (maxPower < val)
9428 val = maxPower;
9429
9431
9432 if (withPowerUpdate)
9433 {
9434 WorldPacket data(SMSG_POWER_UPDATE, 8 + 1 + 4);
9435 data << GetPackGUID();
9436 data << uint8(power);
9437 data << uint32(val);
9439 }
9440
9441 // group update
9442 if (Player* player = ToPlayer())
9443 {
9444 if (player->GetGroup())
9445 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9446 }
9447 else if (Pet* pet = ToCreature()->ToPet())
9448 {
9449 if (pet->isControlled())
9450 {
9451 Unit* owner = GetOwner();
9452 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9454 }
9455
9456 // Update the pet's character sheet with happiness damage bonus
9457 if (pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
9458 pet->UpdateDamagePhysical(BASE_ATTACK);
9459 }
9460}
9461
9463{
9464 uint32 cur_power = GetPower(power);
9466
9467 // group update
9468 if (GetTypeId() == TYPEID_PLAYER)
9469 {
9470 if (ToPlayer()->GetGroup())
9472 }
9473 else if (Pet* pet = ToCreature()->ToPet())
9474 {
9475 if (pet->isControlled())
9476 {
9477 Unit* owner = GetOwner();
9478 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9480 }
9481 }
9482
9483 if (val < cur_power)
9484 SetPower(power, val);
9485}
9486
9488{
9489 // Only hunter pets have POWER_FOCUS and POWER_HAPPINESS
9490 switch (power)
9491 {
9492 case POWER_MANA:
9493 return GetCreateMana();
9494 case POWER_RAGE:
9495 return 1000;
9496 case POWER_FOCUS:
9497 return (GetTypeId() != TYPEID_UNIT || !ToCreature()->IsPet() || ToPet()->getPetType() != HUNTER_PET) ? 0 : 100;
9498 case POWER_ENERGY:
9499 return 100;
9500 case POWER_HAPPINESS:
9501 return (GetTypeId() != TYPEID_UNIT || !ToCreature()->IsPet() || ToPet()->getPetType() != HUNTER_PET) ? 0 : 1050000;
9502 case POWER_RUNIC_POWER:
9503 return 1000;
9504 case POWER_RUNE:
9505 case POWER_HEALTH:
9506 return 0;
9507 default:
9508 break;
9509 }
9510
9511 return 0;
9512}
9513
9515{
9516 if (UnitAI* ai = GetAI())
9517 {
9518 m_aiLocked = true;
9519 ai->UpdateAI(diff);
9520 m_aiLocked = false;
9521 }
9522}
9523
9525{
9526 i_AIs.emplace(newAI);
9527}
9528
9530{
9531 PushAI(newAI);
9532 RefreshAI();
9533}
9534
9536{
9537 if (!i_AIs.empty())
9538 {
9539 i_AIs.pop();
9540 return true;
9541 }
9542 else
9543 return false;
9544}
9545
9547{
9548 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
9549 if (i_AIs.empty())
9550 i_AI = nullptr;
9551 else
9552 i_AI = i_AIs.top();
9553}
9554
9556{
9557 bool const charmed = IsCharmed();
9558
9559 if (charmed)
9561 else
9562 {
9564 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
9565 }
9566}
9567
9569{
9570 // Keep popping the stack until we either reach the bottom or find a valid AI
9571 while (PopAI())
9572 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
9573 return;
9574}
9575
9577{
9578 if (Creature* creature = ToCreature())
9579 return new ScheduledChangeAI(creature);
9580 else
9581 return nullptr;
9582}
9583
9585{
9586 if (UnitAI* ai = GetAI())
9587 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
9588 else
9589 return true;
9590}
9591
9593{
9594 if (IsInWorld())
9595 return;
9596
9599}
9600
9602{
9603 // cleanup
9604 ASSERT(GetGUID());
9605
9606 if (IsInWorld())
9607 {
9609 if (UnitAI* ai = GetAI())
9610 ai->OnDespawn();
9611
9612 if (IsVehicle())
9614
9618
9621
9622 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
9625
9627
9629
9630 if (IsCharmed())
9631 RemoveCharmedBy(nullptr);
9632
9633 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
9634 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
9635
9636 if (Unit* owner = GetOwner())
9637 {
9638 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
9639 {
9640 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
9641 ABORT();
9642 }
9643 }
9644
9647 }
9648}
9649
9651{
9652 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
9654
9655 if (IsInWorld())
9657 else
9658 {
9659 // cleanup that must happen even if not in world
9660 if (IsVehicle())
9662 }
9663
9664 ASSERT(GetGUID());
9665
9666 // A unit may be in removelist and not in world, but it is still in grid
9667 // and may have some references during delete
9670
9671 if (finalCleanup)
9672 m_cleanupDone = true;
9673
9674 CombatStop();
9677}
9678
9679void Unit::CleanupsBeforeDelete(bool finalCleanup)
9680{
9681 CleanupBeforeRemoveFromMap(finalCleanup);
9682
9684}
9685
9687{
9688 if (IsCharmed())
9689 {
9690 UnitAI* newAI = nullptr;
9691 if (GetTypeId() == TYPEID_PLAYER)
9692 {
9693 if (Unit* charmer = GetCharmer())
9694 {
9695 // first, we check if the creature's own AI specifies an override playerai for its owned players
9696 if (Creature* creatureCharmer = charmer->ToCreature())
9697 {
9698 if (CreatureAI* charmerAI = creatureCharmer->AI())
9699 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
9700 }
9701 else
9702 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
9703 }
9704 if (!newAI) // otherwise, we default to the generic one
9705 newAI = new SimpleCharmedPlayerAI(ToPlayer());
9706 }
9707 else
9708 {
9710 if (isPossessed() || IsVehicle())
9711 newAI = new PossessedAI(ToCreature());
9712 else
9713 newAI = new PetAI(ToCreature());
9714 }
9715
9716 ASSERT(newAI);
9717 SetAI(newAI);
9718 newAI->OnCharmed(true);
9719 }
9720 else
9721 {
9723 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
9724 RefreshAI();
9725 if (UnitAI* ai = GetAI())
9726 ai->OnCharmed(true);
9727 }
9728}
9729
9731{
9732 if (!m_charmInfo)
9733 m_charmInfo = new CharmInfo(this);
9734
9735 return m_charmInfo;
9736}
9737
9739{
9740 if (!m_charmInfo)
9741 return;
9742
9744 delete m_charmInfo;
9745 m_charmInfo = nullptr;
9746}
9747
9749: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE),
9750 _isCommandAttack(false), _isCommandFollow(false), _isAtStay(false), _isFollowing(false), _isReturning(false),
9751 _stayX(0.0f), _stayY(0.0f), _stayZ(0.0f)
9752{
9753 for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
9754 _charmspells[i].SetActionAndType(0, ACT_DISABLED);
9755
9756 if (Creature* creature = _unit->ToCreature())
9757 {
9758 _oldReactState = creature->GetReactState();
9759 creature->SetReactState(REACT_PASSIVE);
9760 }
9761}
9762
9764
9766{
9767 if (Creature* creature = _unit->ToCreature())
9768 creature->SetReactState(_oldReactState);
9769}
9770
9772{
9773 // the first 3 SpellOrActions are attack, follow and stay
9776
9777 // middle 4 SpellOrActions are spells/special attacks/abilities
9780
9781 // last 3 SpellOrActions are reactions
9784}
9785
9795
9797{
9798 if (_unit->GetTypeId() == TYPEID_UNIT)
9799 {
9800 // Adding switch until better way is found. Malcrom
9801 // Adding entrys to this switch will prevent COMMAND_ATTACK being added to pet bar.
9802 switch (_unit->GetEntry())
9803 {
9804 case 23575: // Mindless Abomination
9805 case 24783: // Trained Rock Falcon
9806 case 27664: // Crashin' Thrashin' Racer
9807 case 40281: // Crashin' Thrashin' Racer
9808 case 28511: // Eye of Acherus
9809 break;
9810 default:
9812 break;
9813 }
9814
9815 for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
9816 {
9817 uint32 spellId = _unit->ToCreature()->m_spells[i];
9818 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
9819 if (spellInfo)
9820 {
9821 if (spellInfo->IsPassive())
9822 _unit->CastSpell(_unit, spellInfo->Id, true);
9823 else
9825 }
9826 }
9827 }
9828 else
9830}
9831
9833{
9834 if (_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
9835 {
9837 return;
9838 }
9839
9841
9842 for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
9843 {
9844 uint32 spellId = _unit->ToCreature()->m_spells[x];
9845 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
9846
9847 if (!spellInfo)
9848 {
9850 continue;
9851 }
9852
9853 if (spellInfo->IsPassive())
9854 {
9855 _unit->CastSpell(_unit, spellInfo->Id, true);
9857 }
9858 else
9859 {
9861
9862 ActiveStates newstate = ACT_PASSIVE;
9863
9864 if (!spellInfo->IsAutocastable())
9865 newstate = ACT_PASSIVE;
9866 else
9867 {
9868 if (spellInfo->NeedsExplicitUnitTarget())
9869 {
9870 newstate = ACT_ENABLED;
9871 ToggleCreatureAutocast(spellInfo, true);
9872 }
9873 else
9874 newstate = ACT_DISABLED;
9875 }
9876
9877 AddSpellToActionBar(spellInfo, newstate);
9878 }
9879 }
9880}
9881
9882bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate, uint8 preferredSlot)
9883{
9884 uint32 spell_id = spellInfo->Id;
9885 uint32 first_id = spellInfo->GetFirstRankSpell()->Id;
9886
9887 ASSERT(preferredSlot < MAX_UNIT_ACTION_BAR_INDEX);
9888 // new spell rank can be already listed
9889 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9890 {
9891 if (uint32 action = PetActionBar[i].GetAction())
9892 {
9893 if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
9894 {
9895 PetActionBar[i].SetAction(spell_id);
9896 return true;
9897 }
9898 }
9899 }
9900
9901 // or use empty slot in other case
9902 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9903 {
9904 uint8 j = (preferredSlot + i) % MAX_UNIT_ACTION_BAR_INDEX;
9905 if (!PetActionBar[j].GetAction() && PetActionBar[j].IsActionBarForSpell())
9906 {
9907 SetActionBar(j, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_DISABLED : ACT_PASSIVE : newstate);
9908 return true;
9909 }
9910 }
9911 return false;
9912}
9913
9915{
9916 uint32 first_id = sSpellMgr->GetFirstSpellInChain(spell_id);
9917
9918 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9919 {
9920 if (uint32 action = PetActionBar[i].GetAction())
9921 {
9922 if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
9923 {
9925 return true;
9926 }
9927 }
9928 }
9929
9930 return false;
9931}
9932
9933void CharmInfo::ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply)
9934{
9935 if (spellInfo->IsPassive())
9936 return;
9937
9938 for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
9939 if (spellInfo->Id == _charmspells[x].GetAction())
9941}
9942
9943void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
9944{
9945 _petnumber = petnumber;
9946 if (statwindow)
9948 else
9950}
9951
9952void CharmInfo::LoadPetActionBar(const std::string& data)
9953{
9955
9956 std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false);
9957 if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2)
9958 return; // non critical, will reset to default
9959
9960 auto iter = tokens.begin();
9961 for (uint8 index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++index)
9962 {
9963 Optional<uint8> type = Trinity::StringTo<uint8>(*(iter++));
9964 Optional<uint32> action = Trinity::StringTo<uint32>(*(iter++));
9965
9966 if (!type || !action)
9967 continue;
9968
9969 PetActionBar[index].SetActionAndType(*action, static_cast<ActiveStates>(*type));
9970
9971 // check correctness
9972 if (PetActionBar[index].IsActionBarForSpell())
9973 {
9974 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction());
9975 if (!spellInfo)
9976 SetActionBar(index, 0, ACT_PASSIVE);
9977 else if (!spellInfo->IsAutocastable())
9978 SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE);
9979 }
9980 }
9981}
9982
9984{
9985 for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9986 *data << uint32(PetActionBar[i].packedData);
9987}
9988
9989void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state)
9990{
9991 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9992 {
9993 if (spellInfo->Id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
9994 {
9996 break;
9997 }
9998 }
9999}
10000
10002{
10003 uint32 hitMask = PROC_HIT_NONE;
10004 // Check victim state
10005 if (missCondition != SPELL_MISS_NONE)
10006 {
10007 switch (missCondition)
10008 {
10009 case SPELL_MISS_MISS:
10010 hitMask |= PROC_HIT_MISS;
10011 break;
10012 case SPELL_MISS_DODGE:
10013 hitMask |= PROC_HIT_DODGE;
10014 break;
10015 case SPELL_MISS_PARRY:
10016 hitMask |= PROC_HIT_PARRY;
10017 break;
10018 case SPELL_MISS_BLOCK:
10019 // spells can't be partially blocked (it's damage can though)
10021 break;
10022 case SPELL_MISS_EVADE:
10023 hitMask |= PROC_HIT_EVADE;
10024 break;
10025 case SPELL_MISS_IMMUNE:
10026 case SPELL_MISS_IMMUNE2:
10027 hitMask |= PROC_HIT_IMMUNE;
10028 break;
10029 case SPELL_MISS_DEFLECT:
10030 hitMask |= PROC_HIT_DEFLECT;
10031 break;
10032 case SPELL_MISS_ABSORB:
10033 hitMask |= PROC_HIT_ABSORB;
10034 break;
10035 case SPELL_MISS_REFLECT:
10036 hitMask |= PROC_HIT_REFLECT;
10037 break;
10038 case SPELL_MISS_RESIST:
10039 hitMask |= PROC_HIT_FULL_RESIST;
10040 break;
10041 default:
10042 break;
10043 }
10044 }
10045 else
10046 {
10047 // On block
10048 if (damageInfo->blocked)
10049 {
10050 hitMask |= PROC_HIT_BLOCK;
10051 if (damageInfo->fullBlock)
10052 hitMask |= PROC_HIT_FULL_BLOCK;
10053 }
10054 // On absorb
10055 if (damageInfo->absorb)
10056 hitMask |= PROC_HIT_ABSORB;
10057
10058 // Don't set hit/crit hitMask if damage is nullified
10059 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
10060 if (!damageNullified)
10061 {
10062 // On crit
10063 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10064 hitMask |= PROC_HIT_CRITICAL;
10065 else
10066 hitMask |= PROC_HIT_NORMAL;
10067 }
10068 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
10069 hitMask |= PROC_HIT_FULL_RESIST;
10070 }
10071
10072 return hitMask;
10073}
10074
10075void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType)
10076{
10077 // Player is loaded now - do not allow passive spell casts to proc
10078 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
10079 return;
10080
10081 // For melee/ranged based attack need update skills and set some Aura states if victim present
10082 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
10083 {
10084 // Update skills here for players
10085 // only when you are not fighting other players or their pets/totems (pvp)
10086 if (GetTypeId() == TYPEID_PLAYER &&
10087 procTarget->GetTypeId() != TYPEID_PLAYER &&
10088 !(procTarget->IsTotem() && procTarget->ToTotem()->GetOwner()->IsPlayer()) &&
10089 !procTarget->IsPet()
10090 )
10091 {
10092 // On melee based hit/miss/resist need update skill (for victim and attacker)
10094 {
10095 if (procTarget->GetTypeId() != TYPEID_PLAYER && !procTarget->IsCritter())
10096 ToPlayer()->UpdateCombatSkills(procTarget, attType, isVictim);
10097 }
10098 // Update defense if player is victim and parry/dodge/block
10099 else if (isVictim && (hitMask & (PROC_HIT_DODGE | PROC_HIT_PARRY | PROC_HIT_BLOCK)))
10100 ToPlayer()->UpdateCombatSkills(procTarget, attType, true);
10101 }
10102 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10104 {
10105 // for victim
10106 if (isVictim)
10107 {
10108 // if victim and dodge attack
10109 if (hitMask & PROC_HIT_DODGE)
10110 {
10111 // Update AURA_STATE on dodge
10112 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
10113 {
10116 }
10117 }
10118 // if victim and parry attack
10119 if (hitMask & PROC_HIT_PARRY)
10120 {
10121 // For Hunters only Counterattack (skip Mongoose bite)
10122 if (GetClass() == CLASS_HUNTER)
10123 {
10126 }
10127 else
10128 {
10131 }
10132 }
10133 // if and victim block attack
10134 if (hitMask & PROC_HIT_BLOCK)
10135 {
10138 }
10139 }
10140 else // For attacker
10141 {
10142 // Overpower on victim dodge
10143 if ((hitMask & PROC_HIT_DODGE) && GetTypeId() == TYPEID_PLAYER && GetClass() == CLASS_WARRIOR)
10144 {
10145 AddComboPoints(procTarget, 1);
10147 }
10148 else if ((hitMask & PROC_HIT_CRITICAL) && IsHunterPet())
10149 {
10150 AddComboPoints(procTarget, 1);
10152 }
10153 }
10154 }
10155 }
10156}
10157
10159{
10160 TimePoint now = GameTime::Now();
10161
10162 // use provided list of auras which can proc
10163 if (procAuras)
10164 {
10165 for (AuraApplication* aurApp : *procAuras)
10166 {
10167 ASSERT(aurApp->GetTarget() == this);
10168 if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
10169 {
10170 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
10171 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
10172 }
10173 }
10174 }
10175 // or generate one on our own
10176 else
10177 {
10178 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
10179 {
10180 if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now))
10181 {
10182 itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
10183 aurasTriggeringProc.emplace_back(procEffectMask, itr->second);
10184 }
10185 }
10186 }
10187}
10188
10189void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
10190{
10191 // prepare data for self trigger
10192 ProcEventInfo myProcEventInfo(this, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10193 if (typeMaskActor)
10194 {
10195 AuraApplicationProcContainer myAurasTriggeringProc;
10196 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo);
10197
10198 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
10199 if (Player* modOwner = GetSpellModOwner())
10200 {
10201 if (modOwner != this && spell)
10202 {
10203 AuraApplicationList modAuras;
10204 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
10205 {
10206 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
10207 modAuras.push_back(itr->second);
10208 }
10209 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
10210 }
10211 }
10212 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
10213 }
10214
10215 // prepare data for target trigger
10216 ProcEventInfo targetProcEventInfo(this, actionTarget, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10217 if (typeMaskActionTarget && actionTarget)
10218 {
10219 AuraApplicationProcContainer targetAurasTriggeringProc;
10220 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo);
10221 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
10222 }
10223}
10224
10226{
10227 Spell const* triggeringSpell = eventInfo.GetProcSpell();
10228 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
10229 if (disableProcs)
10230 SetCantProc(true);
10231
10232 for (auto const& aurAppProc : aurasTriggeringProc)
10233 {
10234 AuraApplication* aurApp;
10235 uint8 procEffectMask;
10236 std::tie(procEffectMask, aurApp) = aurAppProc;
10237
10238 if (aurApp->GetRemoveMode())
10239 continue;
10240
10241 SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
10242 if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
10243 SetCantProc(true);
10244
10245 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
10246
10247 if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
10248 SetCantProc(false);
10249 }
10250
10251 if (disableProcs)
10252 SetCantProc(false);
10253}
10254
10257{
10258 Unit* owner = GetOwner();
10259 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10260 return;
10261
10262 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10263 petActionFeedback.SpellID = spellId;
10264 petActionFeedback.Response = msg;
10265 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10266}
10267
10269{
10270 WorldPackets::Pet::PetActionSound petActionSound;
10271 petActionSound.UnitGUID = GetGUID();
10272 petActionSound.Action = action;
10273 SendMessageToSet(petActionSound.Write(), false);
10274}
10275
10277{
10278 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId());
10279 if (!displayInfo)
10280 return;
10281
10282 WorldPackets::Pet::PetDismissSound petDismissSound;
10283 petDismissSound.ModelId = displayInfo->ModelID;
10284 petDismissSound.ModelPosition = GetPosition();
10285 SendMessageToSet(petDismissSound.Write(), false);
10286}
10287
10289{
10290 Unit* owner = GetOwner();
10291 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10292 return;
10293
10294 WorldPacket data(SMSG_AI_REACTION, 8 + 4);
10295 data << guid;
10296 data << uint32(AI_REACTION_HOSTILE);
10297 owner->ToPlayer()->SendDirectMessage(&data);
10298}
10299
10301
10306
10311
10312void Unit::StopMoving(bool force /*= false*/)
10313{
10315
10316 // not need send any packets if not in world or not moving
10317 if (!IsInWorld() || (!force && movespline->Finalized()))
10318 return;
10319
10320 // Update position now since Stop does not start a new movement that can be updated later
10321 if (movespline->HasStarted())
10323 Movement::MoveSplineInit init(this);
10324 init.Stop(force);
10325}
10326
10327void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10328{
10329 if (IsInvalidMovementSlot(slot))
10330 return;
10331
10332 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10333 movementGenerator->Pause(timer);
10334
10335 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10336 StopMoving();
10337}
10338
10339void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10340{
10341 if (IsInvalidMovementSlot(slot))
10342 return;
10343
10344 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10345 movementGenerator->Resume(timer);
10346}
10347
10356
10358{
10359 uint8 s = GetStandState();
10361}
10362
10364{
10366
10367 if (state == UNIT_STAND_STATE_STAND)
10369
10370 if (GetTypeId() == TYPEID_PLAYER)
10371 {
10373 data << (uint8)state;
10374 ToPlayer()->SendDirectMessage(&data);
10375 }
10376}
10377
10379{
10380 uint32 transformId = GetTransformSpell();
10381 if (!transformId)
10382 return false;
10383
10384 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId);
10385 if (!spellInfo)
10386 return false;
10387
10388 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10389}
10390
10392{
10393 if (!IsCreature())
10394 return;
10395
10397}
10398
10400{
10402 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10403 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1 : 0.01;
10404 SetObjectScale(std::max(scale, scaleMin));
10405}
10406
10408{
10410 // Set Gender by modelId
10411 if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId))
10412 SetGender(Gender(minfo->gender));
10413}
10414
10416{
10417 AuraEffect* handledAura = nullptr;
10418 // try to receive model from transform auras
10420 if (!transforms.empty())
10421 {
10422 // iterate over already applied transform auras - from newest to oldest
10423 for (auto i = transforms.rbegin(); i != transforms.rend(); ++i)
10424 {
10425 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10426 {
10427 if (!handledAura)
10428 handledAura = (*i);
10429 // prefer negative auras
10430 if (!aurApp->IsPositive())
10431 {
10432 handledAura = (*i);
10433 break;
10434 }
10435 }
10436 }
10437 }
10438
10440
10441 // transform aura was found
10442 if (handledAura)
10443 {
10444 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10445 return;
10446 }
10447 else if (!shapeshiftAura.empty()) // we've found shapeshift
10448 {
10449 // only one such aura possible at a time
10450 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10451 {
10452 SetDisplayId(modelId);
10453 return;
10454 }
10455 }
10456
10457 // no auras found - set modelid to default
10459}
10460
10461void Unit::AddComboPoints(Unit* target, int8 count)
10462{
10463 if (!count)
10464 return;
10465
10466 if (target && target != m_comboTarget)
10467 {
10468 if (m_comboTarget)
10470 m_comboTarget = target;
10471 m_comboPoints = count;
10472 target->AddComboPointHolder(this);
10473 }
10474 else
10475 m_comboPoints = std::max<int8>(std::min<int8>(m_comboPoints + count, 5),0);
10476
10478}
10479
10481{
10482 if (!m_comboTarget)
10483 return;
10484
10485 // remove Premed-like effects
10486 // (NB: this Aura retains the CP while it's active - now that CP have reset, it shouldn't be there anymore)
10488
10489 m_comboPoints = 0;
10492 m_comboTarget = nullptr;
10493}
10494
10496{
10497 if (m_cleanupDone)
10498 return;
10499
10501 if (Player* playerMe = ToPlayer())
10502 {
10503 WorldPacket data;
10504 data.Initialize(SMSG_UPDATE_COMBO_POINTS, packGUID.size() + 1);
10505 data << packGUID;
10506 data << uint8(m_comboPoints);
10507 playerMe->SendDirectMessage(&data);
10508 }
10509 Player* movingMe = GetCharmerOrSelfPlayer();
10510 ObjectGuid ownerGuid = GetCharmerOrOwnerGUID();
10511 Player* owner = nullptr;
10512 if (ownerGuid.IsPlayer())
10513 owner = ObjectAccessor::GetPlayer(*this, ownerGuid);
10514 if (movingMe || owner)
10515 {
10516 WorldPacket data;
10517 data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, GetPackGUID().size() + packGUID.size() + 1);
10518 data << GetPackGUID();
10519 data << packGUID;
10520 data << uint8(m_comboPoints);
10521 if (movingMe)
10522 movingMe->SendDirectMessage(&data);
10523 if (owner && owner != movingMe)
10524 owner->SendDirectMessage(&data);
10525 }
10526}
10527
10529{
10530 while (!m_ComboPointHolders.empty())
10531 (*m_ComboPointHolders.begin())->ClearComboPoints(); // this also removes it from m_comboPointHolders
10532}
10533
10535{
10536 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10537 m_reactiveTimer[i] = 0;
10538
10545 if (IsHunterPet())
10547}
10548
10550{
10551 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10552 {
10553 ReactiveType reactive = ReactiveType(i);
10554
10555 if (!m_reactiveTimer[reactive])
10556 continue;
10557
10558 if (m_reactiveTimer[reactive] <= p_time)
10559 {
10560 m_reactiveTimer[reactive] = 0;
10561
10562 switch (reactive)
10563 {
10564 case REACTIVE_DEFENSE:
10567 break;
10571 break;
10572 case REACTIVE_OVERPOWER:
10575 break;
10577 if (IsHunterPet())
10579 break;
10580 default:
10581 break;
10582 }
10583 }
10584 else
10585 {
10586 m_reactiveTimer[reactive] -= p_time;
10587 }
10588 }
10589}
10590
10591Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10592{
10593 std::list<Unit*> targets;
10594 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10596 Cell::VisitAllObjects(this, searcher, dist);
10597
10598 // remove current target
10599 if (GetVictim())
10600 targets.remove(GetVictim());
10601
10602 if (exclude)
10603 targets.remove(exclude);
10604
10605 // remove not LoS targets
10606 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10607 {
10608 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10609 targets.erase(tIter++);
10610 else
10611 ++tIter;
10612 }
10613
10614 // no appropriate targets
10615 if (targets.empty())
10616 return nullptr;
10617
10618 // select random
10620}
10621
10622void ApplyPercentModFloatVar(float& var, float val, bool apply)
10623{
10624 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
10625}
10626
10628{
10630
10631 float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]);
10632 if (val > 0.f)
10633 {
10635 ApplyPercentModFloatVar(amount, val, !apply);
10636 }
10637 else
10638 {
10640 ApplyPercentModFloatVar(amount, -val, apply);
10641 }
10642
10644 m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct);
10645}
10646
10647void Unit::ApplyCastTimePercentMod(float val, bool apply)
10648{
10649 float amount = GetFloatValue(UNIT_MOD_CAST_SPEED);
10650
10651 if (val > 0.f)
10652 ApplyPercentModFloatVar(amount, val, !apply);
10653 else
10654 ApplyPercentModFloatVar(amount, -val, apply);
10655
10656 SetModCastingSpeed(amount);
10657}
10658
10659uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const
10660{
10661 // Not apply this to creature cast spells with casttime == 0
10662 if (CastingTime == 0 && GetTypeId() == TYPEID_UNIT && !IsPet())
10663 return 3500;
10664
10665 if (CastingTime > 7000) CastingTime = 7000;
10666 if (CastingTime < 1500) CastingTime = 1500;
10667
10668 if (damagetype == DOT && !spellProto->IsChanneled())
10669 CastingTime = 3500;
10670
10671 int32 overTime = 0;
10672 uint8 effects = 0;
10673 bool DirectDamage = false;
10674 bool AreaEffect = false;
10675
10676 for (SpellEffectInfo const& spellEffectInfo : spellProto->GetEffects())
10677 {
10678 switch (spellEffectInfo.Effect)
10679 {
10685 case SPELL_EFFECT_HEAL:
10686 DirectDamage = true;
10687 break;
10689 switch (spellEffectInfo.ApplyAuraName)
10690 {
10694 if (spellProto->GetDuration())
10695 overTime = spellProto->GetDuration();
10696 break;
10697 default:
10698 // -5% per additional effect
10699 ++effects;
10700 break;
10701 }
10702 break;
10703 default:
10704 break;
10705 }
10706
10707 if (spellEffectInfo.IsTargetingArea())
10708 AreaEffect = true;
10709 }
10710
10711 // Combined Spells with Both Over Time and Direct Damage
10712 if (overTime > 0 && DirectDamage)
10713 {
10714 // mainly for DoTs which are 3500 here otherwise
10715 uint32 OriginalCastTime = spellProto->CalcCastTime();
10716 if (OriginalCastTime > 7000) OriginalCastTime = 7000;
10717 if (OriginalCastTime < 1500) OriginalCastTime = 1500;
10718 // Portion to Over Time
10719 float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f));
10720
10721 if (damagetype == DOT)
10722 CastingTime = uint32(CastingTime * PtOT);
10723 else if (PtOT < 1.0f)
10724 CastingTime = uint32(CastingTime * (1 - PtOT));
10725 else
10726 CastingTime = 0;
10727 }
10728
10729 // Area Effect Spells receive only half of bonus
10730 if (AreaEffect)
10731 CastingTime /= 2;
10732
10733 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
10734 for (SpellEffectInfo const& spellEffectInfo : spellProto->GetEffects())
10735 {
10736 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEALTH_LEECH) ||
10737 (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH))
10738 {
10739 CastingTime /= 2;
10740 break;
10741 }
10742 }
10743
10744 // -5% of total per any additional effect
10745 for (uint8 i = 0; i < effects; ++i)
10746 CastingTime *= 0.95f;
10747
10748 return CastingTime;
10749}
10750
10752{
10753 if (slot >= MAX_AURAS) // slot not found, return
10754 return;
10755 if (Player* player = ToPlayer())
10756 {
10757 if (player->GetGroup())
10758 {
10759 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
10760 player->SetAuraUpdateMaskForRaid(slot);
10761 }
10762 }
10763 else if (GetTypeId() == TYPEID_UNIT && IsPet())
10764 {
10765 Pet* pet = ((Pet*)this);
10766 if (pet->isControlled())
10767 {
10768 Unit* owner = GetOwner();
10769 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
10770 {
10772 pet->SetAuraUpdateMaskForRaid(slot);
10773 }
10774 }
10775 }
10776}
10777
10778void Unit::SetCantProc(bool apply)
10779{
10780 if (apply)
10781 ++m_procDeep;
10782 else
10783 {
10785 --m_procDeep;
10786 }
10787}
10788
10789float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const
10790{
10791 // Damage over Time spells bonus calculation
10792 float DotFactor = 1.0f;
10793 if (damagetype == DOT)
10794 {
10795 int32 DotDuration = spellInfo->GetDuration();
10796 if (!spellInfo->IsChanneled() && DotDuration > 0)
10797 DotFactor = DotDuration / 15000.0f;
10798
10799 if (uint32 DotTicks = spellInfo->GetMaxTicks())
10800 DotFactor /= DotTicks;
10801 }
10802
10803 int32 CastingTime = spellInfo->IsChanneled() ? spellInfo->GetDuration() : spellInfo->CalcCastTime();
10804 // Distribute Damage over multiple effects, reduce by AoE
10805 CastingTime = GetCastingTimeForBonus(spellInfo, damagetype, CastingTime);
10806
10807 // As wowwiki says: C = (Cast Time / 3.5)
10808 return (CastingTime / 3500.0f) * DotFactor;
10809}
10810
10811float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
10812{
10813 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
10814 return GetAttackTime(attType) / 1000.0f;
10815
10816 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
10817 if (!weapon)
10818 return BASE_ATTACK_TIME / 1000.0f;
10819
10820 if (!normalized)
10821 return weapon->GetTemplate()->Delay / 1000.0f;
10822
10823 switch (weapon->GetTemplate()->SubClass)
10824 {
10831 return 3.3f;
10836 return 2.8f;
10843 return 2.4f;
10845 return 1.7f;
10846 default:
10847 return weapon->GetTemplate()->Delay / 1000.0f;
10848 }
10849}
10850
10852{
10854}
10855
10856Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
10857{
10858 if (GetTypeId() != TYPEID_PLAYER)
10859 return nullptr;
10860
10861 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10862
10863 if (!pet->CreateBaseAtCreature(creatureTarget))
10864 {
10865 delete pet;
10866 return nullptr;
10867 }
10868
10869 uint8 level = creatureTarget->GetLevel() + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget->GetLevel();
10870
10871 if (!InitTamedPet(pet, level, spell_id))
10872 {
10873 delete pet;
10874 return nullptr;
10875 }
10876
10877 return pet;
10878}
10879
10881{
10882 if (GetTypeId() != TYPEID_PLAYER)
10883 return nullptr;
10884
10885 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
10886 if (!creatureInfo)
10887 return nullptr;
10888
10889 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10890
10891 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
10892 {
10893 delete pet;
10894 return nullptr;
10895 }
10896
10897 return pet;
10898}
10899
10900bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
10901{
10902 Player* player = ToPlayer();
10903 PetStable& petStable = player->GetOrInitPetStable();
10904 if (petStable.CurrentPet || petStable.GetUnslottedHunterPet())
10905 return false;
10906
10907 pet->SetCreatorGUID(GetGUID());
10908 pet->SetFaction(GetFaction());
10909 pet->SetCreatedBySpell(spell_id);
10910
10911 if (GetTypeId() == TYPEID_PLAYER)
10913
10914 if (!pet->InitStatsForLevel(level))
10915 {
10916 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
10917 return false;
10918 }
10919
10920 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
10921 // this enables pet details window (Shift+P)
10922 pet->InitPetCreateSpells();
10923 //pet->InitLevelupSpellsForLevel();
10924 pet->SetFullHealth();
10925
10926 pet->FillPetInfo(&petStable.CurrentPet.emplace());
10927 return true;
10928}
10929
10930/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/)
10931{
10932 // Prevent killing unit twice (and giving reward from kill twice)
10933 if (!victim->GetHealth())
10934 return;
10935
10936 if (attacker && !attacker->IsInMap(victim))
10937 attacker = nullptr;
10938
10939 // find player: owner of controlled `this` or `this` itself maybe
10940 Player* player = nullptr;
10941 if (attacker)
10942 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
10943
10944 Creature* creature = victim->ToCreature();
10945
10946 bool isRewardAllowed = true;
10947 if (creature)
10948 {
10949 isRewardAllowed = creature->IsDamageEnoughForLootingAndReward();
10950 if (!isRewardAllowed)
10951 creature->SetLootRecipient(nullptr);
10952 }
10953
10954 if (isRewardAllowed && creature)
10955 {
10956 if (Player* lootRecipient = creature->GetLootRecipient())
10957 {
10958 // Loot recipient can be in a different map
10959 if (!creature->IsInMap(lootRecipient))
10960 {
10961 if (Group* group = creature->GetLootRecipientGroup())
10962 {
10963 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
10964 {
10965 Player* member = itr->GetSource();
10966 if (!member || !creature->IsInMap(member))
10967 continue;
10968
10969 player = member;
10970 break;
10971 }
10972 }
10973 }
10974 else
10975 player = creature->GetLootRecipient();
10976 }
10977 }
10978
10979 // Exploit fix
10980 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
10981 isRewardAllowed = false;
10982
10983 // Reward player, his pets, and group/raid members
10984 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
10985 if (isRewardAllowed && player && player != victim)
10986 {
10987 WorldPacket data(SMSG_PARTYKILLLOG, (8+8)); // send event PARTY_KILL
10988 data << player->GetGUID(); // player with killing blow
10989 data << victim->GetGUID(); // victim
10990
10991 Player* looter = player;
10992 Group* group = player->GetGroup();
10993 bool hasLooterGuid = false;
10994
10995 if (group)
10996 {
10997 group->BroadcastPacket(&data, group->GetMemberGroup(player->GetGUID()) != 0);
10998
10999 if (creature)
11000 {
11001 group->UpdateLooterGuid(creature, true);
11002 if (!group->GetLooterGuid().IsEmpty())
11003 {
11004 looter = ObjectAccessor::FindPlayer(group->GetLooterGuid());
11005 if (looter)
11006 {
11007 hasLooterGuid = true;
11008 creature->SetLootRecipient(looter); // update creature loot recipient to the allowed looter.
11009 }
11010 }
11011 }
11012 }
11013 else
11014 {
11015 player->SendDirectMessage(&data);
11016
11017 if (creature)
11018 {
11019 WorldPacket data2(SMSG_LOOT_LIST, 8 + 1 + 1);
11020 data2 << creature->GetGUID();
11021 data2 << uint8(0); // unk1
11022 data2 << uint8(0); // no group looter
11023 player->SendMessageToSet(&data2, true);
11024 }
11025 }
11026
11027 // Generate loot before updating looter
11028 if (creature)
11029 {
11030 Loot* loot = &creature->loot;
11031 loot->clear();
11032
11033 if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
11034 loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode());
11035
11036 if (creature->GetLootMode() > 0)
11038
11039 if (group)
11040 {
11041 if (hasLooterGuid)
11042 group->SendLooter(creature, looter);
11043 else
11044 group->SendLooter(creature, nullptr);
11045
11046 // Update round robin looter only if the creature had loot
11047 if (!loot->empty())
11048 group->UpdateLooterGuid(creature);
11049 }
11050 }
11051
11052 player->RewardPlayerAndGroupAtKill(victim, false);
11053 }
11054
11055 // Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
11056 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
11057 {
11058 // proc only once for victim
11059 if (Unit* owner = attacker->GetOwner())
11061 }
11062
11063 if (!victim->IsCritter())
11065
11066 // Proc auras on death - must be before aura/combat remove
11068
11069 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
11070 // and before Spirit of Redemption as it also removes auras
11071 if (attacker)
11072 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
11073 killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim);
11074
11075 // Spirit of Redemption
11076 // if talent known but not triggered
11077 bool spiritOfRedemption = false;
11078 if (AuraEffect const* aurEff = victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_PRIEST, 0, 0, 0x200))
11079 {
11080 // save value before aura remove
11081 uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
11082 if (!ressSpellId)
11083 ressSpellId = victim->ToPlayer()->GetResurrectionSpellId();
11084 // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
11085 victim->RemoveAllAurasOnDeath();
11086 // restore for use at real death
11087 victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
11088
11089 // FORM_SPIRITOFREDEMPTION and related auras
11090 victim->CastSpell(victim, 27827, aurEff);
11091 spiritOfRedemption = true;
11092 }
11093
11094 if (!spiritOfRedemption)
11095 {
11096 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
11097 victim->setDeathState(JUST_DIED);
11098 }
11099
11100 // Inform pets (if any) when player kills target)
11101 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
11102 // selection will get stuck on same target and break pet react state
11103 if (player)
11104 {
11105 Pet* pet = player->GetPet();
11106 if (pet && pet->IsAlive() && pet->isControlled())
11107 {
11108 if (pet->IsAIEnabled())
11109 pet->AI()->KilledUnit(victim);
11110 else
11111 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
11112 }
11113 }
11114
11115 // 10% durability loss on death
11116 if (Player* plrVictim = victim->ToPlayer())
11117 {
11118 // remember victim PvP death for corpse type and corpse reclaim delay
11119 // at original death (not at SpiritOfRedemtionTalent timeout)
11120 plrVictim->SetPvPDeath(player != nullptr);
11121
11122 // only if not player and not controlled by player pet. And not at BG
11123 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
11124 {
11125 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
11126 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", baseLoss);
11127 plrVictim->DurabilityLossAll(baseLoss, false);
11128 // durability lost message
11129 plrVictim->SendDurabilityLoss();
11130 }
11131 // Call KilledUnit for creatures
11132 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11133 attacker->ToCreature()->AI()->KilledUnit(victim);
11134
11135 // last damage from non duel opponent or opponent controlled creature
11136 if (plrVictim->duel)
11137 {
11138 plrVictim->duel->Opponent->CombatStopWithPets(true);
11139 plrVictim->CombatStopWithPets(true);
11140 plrVictim->DuelComplete(DUEL_INTERRUPTED);
11141 }
11142 }
11143 else // creature died
11144 {
11145 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
11146 ASSERT_NODEBUGINFO(creature);
11147
11148 if (!creature->IsPet())
11149 {
11150 // must be after setDeathState which resets dynamic flags
11151 if (!creature->loot.isLooted())
11153 else
11154 creature->AllLootRemovedFromCorpse();
11155 }
11156
11157 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
11158 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11159 attacker->ToCreature()->AI()->KilledUnit(victim);
11160
11161 // Call creature just died function
11162 if (CreatureAI* ai = creature->AI())
11163 ai->JustDied(attacker);
11164
11165 if (TempSummon * summon = creature->ToTempSummon())
11166 {
11167 if (WorldObject * summoner = summon->GetSummoner())
11168 {
11169 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
11170 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
11171 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
11172 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
11173 }
11174 }
11175
11176 // Dungeon specific stuff, only applies to players killing creatures
11177 if (creature->GetInstanceId())
11178 {
11179 Map* instanceMap = creature->GetMap();
11180
11182 if (instanceMap->IsDungeon() && ((attacker && attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) || attacker == victim))
11183 {
11184 if (instanceMap->IsRaidOrHeroicDungeon())
11185 {
11187 instanceMap->ToInstanceMap()->PermBindAllPlayers();
11188 }
11189 else
11190 {
11191 // the reset time is set but not added to the scheduler
11192 // until the players leave the instance
11193 time_t resettime = GameTime::GetGameTime() + 2 * HOUR;
11194 if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(creature->GetInstanceId()))
11195 if (save->GetResetTime() < resettime)
11196 save->SetResetTime(resettime);
11197 }
11198 }
11199 }
11200 }
11201
11202 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
11203 // handle player kill only if not suicide (spirit of redemption for example)
11204 if (player && attacker != victim)
11205 {
11206 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
11207 pvp->HandleKill(player, victim);
11208
11209 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()))
11210 bf->HandleKill(player, victim);
11211 }
11212
11213 //if (victim->GetTypeId() == TYPEID_PLAYER)
11214 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
11215 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
11216
11217 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
11218 if (player && player->InBattleground())
11219 {
11220 if (Battleground* bg = player->GetBattleground())
11221 {
11222 if (Player* playerVictim = victim->ToPlayer())
11223 bg->HandleKillPlayer(playerVictim, player);
11224 else
11225 bg->HandleKillUnit(victim->ToCreature(), player);
11226 }
11227 }
11228
11229 // achievement stuff
11230 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
11231 {
11232 if (attacker->GetTypeId() == TYPEID_UNIT)
11234 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
11236 }
11237
11238 // Hook for OnPVPKill Event
11239 if (attacker)
11240 {
11241 if (Player* killerPlr = attacker->ToPlayer())
11242 {
11243 if (Player* killedPlr = victim->ToPlayer())
11244 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
11245 else if (Creature* killedCre = victim->ToCreature())
11246 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
11247 }
11248 else if (Creature* killerCre = attacker->ToCreature())
11249 {
11250 if (Player* killed = victim->ToPlayer())
11251 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
11252 }
11253 }
11254}
11255
11256void Unit::SetControlled(bool apply, UnitState state)
11257{
11258 if (apply)
11259 {
11260 if (HasUnitState(state))
11261 return;
11262
11263 if (state & UNIT_STATE_CONTROLLED)
11264 CastStop();
11265
11266 AddUnitState(state);
11267 switch (state)
11268 {
11269 case UNIT_STATE_STUNNED:
11270 SetStunned(true);
11271 break;
11272 case UNIT_STATE_ROOT:
11274 SetRooted(true);
11275 break;
11278 {
11281 // SendAutoRepeatCancel ?
11282 SetConfused(true);
11283 }
11284 break;
11285 case UNIT_STATE_FLEEING:
11287 {
11290 // SendAutoRepeatCancel ?
11291 SetFeared(true);
11292 }
11293 break;
11294 default:
11295 break;
11296 }
11297 }
11298 else
11299 {
11300 switch (state)
11301 {
11302 case UNIT_STATE_STUNNED:
11304 return;
11305
11306 ClearUnitState(state);
11307 SetStunned(false);
11308 break;
11309 case UNIT_STATE_ROOT:
11310 if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle() || (ToCreature() && ToCreature()->GetMovementTemplate().IsRooted()))
11311 return;
11312
11313 ClearUnitState(state);
11315 SetRooted(false);
11316 break;
11319 return;
11320
11321 ClearUnitState(state);
11322 SetConfused(false);
11323 break;
11324 case UNIT_STATE_FLEEING:
11326 return;
11327
11328 ClearUnitState(state);
11329 SetFeared(false);
11330 break;
11331 default:
11332 return;
11333 }
11334
11336 }
11337}
11338
11340{
11341 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
11343 SetStunned(true);
11344
11346 SetRooted(true);
11347
11349 SetConfused(true);
11350
11352 SetFeared(true);
11353}
11354
11355void Unit::SetStunned(bool apply)
11356{
11357 if (apply)
11358 {
11361
11362 StopMoving();
11363
11364 if (GetTypeId() == TYPEID_PLAYER)
11366
11367 SetRooted(true);
11368
11369 CastStop();
11370 }
11371 else
11372 {
11373 if (IsAlive() && GetVictim())
11375
11376 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11377 Unit* owner = GetCharmerOrOwner();
11378 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11380
11381 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11382 SetRooted(false);
11383 }
11384}
11385
11386void Unit::SetRooted(bool apply)
11387{
11388 if (apply)
11389 {
11390 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11391 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11392 // setting MOVEMENTFLAG_ROOT
11395 StopMoving();
11396 }
11397 else
11399
11400 static OpcodeServer const rootOpcodeTable[2][3] =
11401 {
11404 };
11405
11406 if (IsMovedByClient())
11407 {
11408 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
11409
11410 WorldPacket data(rootOpcodeTable[apply][1], 10);
11411 data << GetPackGUID();
11412 data << GetMovementCounterAndInc();
11413 playerMover->SendDirectMessage(&data);
11414
11415 data.Initialize(rootOpcodeTable[apply][2], 64);
11416 data << GetPackGUID();
11417 BuildMovementPacket(&data);
11418 SendMessageToSet(&data, playerMover);
11419 }
11420 else
11421 {
11422 WorldPacket data(rootOpcodeTable[apply][0], 9);
11423 data << GetPackGUID();
11424 SendMessageToSet(&data, true);
11425 }
11426}
11427
11428void Unit::SetFeared(bool apply)
11429{
11430 if (apply)
11431 {
11432 // block control to real player in control (eg charmer)
11435
11437
11438 Unit* caster = nullptr;
11440 if (!fearAuras.empty())
11441 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11442 if (!caster)
11443 caster = getAttackerForHelper();
11444 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY) : 0); // caster == NULL processed in MoveFleeing
11445 }
11446 else
11447 {
11448 if (IsAlive())
11449 {
11451 if (GetVictim())
11453 if (!IsPlayer() && !IsInCombat())
11455 }
11456
11457 // allow control to real player in control (eg charmer)
11460 }
11461}
11462
11463void Unit::SetConfused(bool apply)
11464{
11465 if (apply)
11466 {
11467 // block control to real player in control (eg charmer)
11470
11473 }
11474 else
11475 {
11476 if (IsAlive())
11477 {
11479 if (GetVictim())
11481 }
11482
11483 // allow control to real player in control (eg charmer)
11486 }
11487}
11488
11489bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11490{
11491 if (!charmer)
11492 return false;
11493
11494 // dismount players when charmed
11495 if (GetTypeId() == TYPEID_PLAYER)
11497
11498 if (charmer->GetTypeId() == TYPEID_PLAYER)
11500
11501 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11502 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11503
11504 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11505
11506 if (this == charmer)
11507 {
11508 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11509 return false;
11510 }
11511
11512 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11513 // return false;
11514
11516 {
11517 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11518 return false;
11519 }
11520
11521 // Already charmed
11522 if (!GetCharmerGUID().IsEmpty())
11523 {
11524 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11525 return false;
11526 }
11527
11528 CastStop();
11529 AttackStop();
11530
11531 Player* playerCharmer = charmer->ToPlayer();
11532
11533 // Charmer stop charming
11534 if (playerCharmer)
11535 {
11536 playerCharmer->StopCastingCharm();
11537 playerCharmer->StopCastingBindSight();
11538 }
11539
11540 // Charmed stop charming
11541 if (GetTypeId() == TYPEID_PLAYER)
11542 {
11545 }
11546
11547 // StopCastingCharm may remove a possessed pet?
11548 if (!IsInWorld())
11549 {
11550 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11551 return false;
11552 }
11553
11554 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11555 // prevent undefined behaviour
11556 if (aurApp && aurApp->GetRemoveMode())
11557 return false;
11558
11560 SetFaction(charmer->GetFaction());
11561
11562 // Pause any Idle movement
11563 PauseMovement(0, 0, false);
11564
11565 // Remove any active voluntary movement
11567
11568 // Stop any remaining spline, if no involuntary movement is found
11569 auto criteria = [](MovementGenerator const* movement) -> bool
11570 {
11571 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11572 };
11573 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11574 StopMoving();
11575
11576 // Set charmed
11577 charmer->SetCharm(this, true);
11579
11580 if (Player* player = ToPlayer())
11581 {
11582 if (player->isAFK())
11583 player->ToggleAFK();
11584
11585 player->SetClientControl(this, false);
11586 }
11587
11588 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11589 // prevent undefined behaviour
11590 if (aurApp && aurApp->GetRemoveMode())
11591 {
11592 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11595 charmer->SetCharm(this, false);
11596 return false;
11597 }
11598
11599 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11600 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11601 {
11602 InitCharmInfo();
11603 if (type == CHARM_TYPE_POSSESS)
11605 else
11607 }
11608
11609 if (playerCharmer)
11610 {
11611 switch (type)
11612 {
11613 case CHARM_TYPE_VEHICLE:
11615 playerCharmer->SetClientControl(this, true);
11616 playerCharmer->VehicleSpellInitialize();
11617 break;
11618 case CHARM_TYPE_POSSESS:
11621 playerCharmer->SetClientControl(this, true);
11622 playerCharmer->PossessSpellInitialize();
11624 break;
11625 case CHARM_TYPE_CHARM:
11626 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11627 {
11629 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11630 {
11631 // to prevent client crash
11633
11634 // just to enable stat window
11635 if (GetCharmInfo())
11636 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11637
11638 // if charmed two demons the same session, the 2nd gets the 1st one's name
11639 SetPetNameTimestamp(uint32(GameTime::GetGameTime())); // cast can't be helped
11640 }
11641 }
11642 playerCharmer->CharmSpellInitialize();
11643 break;
11644 default:
11645 case CHARM_TYPE_CONVERT:
11646 break;
11647 }
11648 }
11649
11651
11652 if (Creature* creature = ToCreature())
11653 creature->RefreshCanSwimFlag();
11654
11655 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
11656 {
11657 // AI will schedule its own change if appropriate
11658 if (UnitAI* ai = GetAI())
11659 ai->OnCharmed(false);
11660 else
11662 }
11663 return true;
11664}
11665
11667{
11668 if (!IsCharmed())
11669 return;
11670
11671 if (charmer)
11672 ASSERT(charmer == GetCharmer());
11673 else
11674 charmer = GetCharmer();
11675
11676 ASSERT(charmer);
11677
11678 CharmType type;
11680 type = CHARM_TYPE_POSSESS;
11681 else if (charmer->IsOnVehicle(this))
11682 type = CHARM_TYPE_VEHICLE;
11683 else
11684 type = CHARM_TYPE_CHARM;
11685
11686 CastStop();
11687 AttackStop();
11688
11689 if (_oldFactionId)
11690 {
11692 _oldFactionId = 0;
11693 }
11694 else
11696
11697 if (type != CHARM_TYPE_CHARM && !IsPlayer())
11698 {
11699 StopMoving(true);
11700
11701 // Purge flags left over by client control
11703 }
11704
11707
11708 // Vehicle should not attack its passenger after he exists the seat
11709 if (type != CHARM_TYPE_VEHICLE)
11710 LastCharmerGUID = charmer->GetGUID();
11711
11712 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11714
11715 charmer->SetCharm(this, false);
11717
11718 Player* playerCharmer = charmer->ToPlayer();
11719 if (playerCharmer)
11720 {
11721 switch (type)
11722 {
11723 case CHARM_TYPE_VEHICLE:
11724 playerCharmer->SetClientControl(this, false);
11725 playerCharmer->SetClientControl(charmer, true);
11727 break;
11728 case CHARM_TYPE_POSSESS:
11730 playerCharmer->SetClientControl(this, false);
11731 playerCharmer->SetClientControl(charmer, true);
11734 break;
11735 case CHARM_TYPE_CHARM:
11736 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11737 {
11739 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11740 {
11741 SetClass(uint8(cinfo->unit_class));
11742 if (GetCharmInfo())
11743 GetCharmInfo()->SetPetNumber(0, true);
11744 else
11745 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
11746 }
11747 }
11748 break;
11749 case CHARM_TYPE_CONVERT:
11750 break;
11751 }
11752 }
11753
11754 if (Player* player = ToPlayer())
11755 player->SetClientControl(this, true);
11756
11757 if (playerCharmer && this != charmer->GetFirstControlled())
11758 playerCharmer->SendRemoveControlBar();
11759
11760 // a guardian should always have charminfo
11761 if (!IsGuardian())
11763
11764 // reset confused movement for example
11766
11767 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
11768 {
11769 if (UnitAI* charmedAI = GetAI())
11770 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
11771 else
11773 }
11774}
11775
11777{
11778 if (GetTypeId() == TYPEID_PLAYER)
11780 else
11781 {
11783 {
11784 if (Unit* owner = GetOwner())
11785 {
11786 SetFaction(owner->GetFaction());
11787 return;
11788 }
11789 }
11790
11791 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
11792 SetFaction(cinfo->faction);
11793 }
11794}
11795
11796bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry)
11797{
11798 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
11799 if (!vehInfo)
11800 return false;
11801
11802 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
11805 return true;
11806}
11807
11809{
11810 if (!m_vehicleKit)
11811 return;
11812
11814 m_vehicleKit = nullptr;
11815
11816 m_updateFlag &= ~UPDATEFLAG_VEHICLE;
11817 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
11819}
11820
11821bool Unit::IsOnVehicle(Unit const* vehicle) const
11822{
11823 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
11824}
11825
11827{
11828 return m_vehicle ? m_vehicle->GetBase() : nullptr;
11829}
11830
11832{
11833 Unit* vehicleRoot = GetVehicleBase();
11834
11835 if (!vehicleRoot)
11836 return nullptr;
11837
11838 for (;;)
11839 {
11840 if (!vehicleRoot->GetVehicleBase())
11841 return vehicleRoot;
11842
11843 vehicleRoot = vehicleRoot->GetVehicleBase();
11844 }
11845}
11846
11848{
11849 if (Unit* veh = GetVehicleBase())
11850 if (Creature* c = veh->ToCreature())
11851 return c;
11852
11853 return nullptr;
11854}
11855
11857{
11858 if (GetVehicle())
11859 return GetVehicleBase()->GetGUID();
11860 if (GetTransport())
11861 return GetTransport()->GetGUID();
11862
11863 return ObjectGuid::Empty;
11864}
11865
11867{
11868 if (Vehicle* veh = GetVehicle())
11869 return veh;
11870 return GetTransport();
11871}
11872
11873bool Unit::IsInPartyWith(Unit const* unit) const
11874{
11875 if (this == unit)
11876 return true;
11877
11878 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11879 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11880 if (u1 == u2)
11881 return true;
11882
11883 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11884 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
11887 return true;
11888
11889 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11890}
11891
11892bool Unit::IsInRaidWith(Unit const* unit) const
11893{
11894 if (this == unit)
11895 return true;
11896
11897 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11898 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11899 if (u1 == u2)
11900 return true;
11901
11902 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11903 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
11906 return true;
11907
11908 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11909}
11910
11911void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
11912{
11913 Unit* owner = GetCharmerOrOwnerOrSelf();
11914 Group* group = nullptr;
11915 if (owner->GetTypeId() == TYPEID_PLAYER)
11916 group = owner->ToPlayer()->GetGroup();
11917
11918 if (group)
11919 {
11920 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
11921
11922 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
11923 {
11924 Player* Target = itr->GetSource();
11925
11926 // IsHostileTo check duel and controlled by enemy
11927 if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
11928 {
11929 if (Target->IsAlive())
11930 TagUnitMap.push_back(Target);
11931
11932 if (Guardian* pet = Target->GetGuardianPet())
11933 if (pet->IsAlive())
11934 TagUnitMap.push_back(pet);
11935 }
11936 }
11937 }
11938 else
11939 {
11940 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
11941 TagUnitMap.push_back(owner);
11942 if (Guardian* pet = owner->GetGuardianPet())
11943 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
11944 TagUnitMap.push_back(pet);
11945 }
11946}
11947
11949{
11950 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
11951 return entry->IsContestedGuardFaction();
11952
11953 return false;
11954}
11955
11956void Unit::SetPvP(bool state)
11957{
11958 if (state)
11960 else
11962}
11963
11964Aura* Unit::AddAura(uint32 spellId, Unit* target)
11965{
11966 if (!target)
11967 return nullptr;
11968
11969 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
11970 if (!spellInfo)
11971 return nullptr;
11972
11973 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
11974}
11975
11976Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target)
11977{
11978 if (!spellInfo)
11979 return nullptr;
11980
11981 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
11982 return nullptr;
11983
11984 if (target->IsImmunedToSpell(spellInfo, this))
11985 return nullptr;
11986
11987 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
11988 {
11989 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
11990 continue;
11991
11992 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
11993 effMask &= ~(1 << spellEffectInfo.EffectIndex);
11994 }
11995
11996 if (!effMask)
11997 return nullptr;
11998
11999 AuraCreateInfo createInfo(spellInfo, effMask, target);
12000 createInfo.SetCaster(this);
12001
12002 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
12003 {
12004 aura->ApplyForTargets();
12005 return aura;
12006 }
12007 return nullptr;
12008}
12009
12010void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
12011{
12012 Aura* aura = target->GetAura(spellId, GetGUID());
12013 if (!aura)
12014 aura = AddAura(spellId, target);
12015 if (aura && stack)
12016 aura->SetStackAmount(stack);
12017}
12018
12020{
12021 WorldPackets::Spells::PlaySpellVisualKit playSpellVisualKit(type);
12022 playSpellVisualKit.Unit = GetGUID();
12023 playSpellVisualKit.KitRecID = id;
12024 SendMessageToSet(playSpellVisualKit.Write(), true);
12025}
12026
12028{
12029 return !IsVehicle() && GetOwnerGUID().IsPlayer();
12030}
12031
12032/*static*/ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type)
12033{
12034 // player mounted on multi-passenger mount is also classified as vehicle
12035 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
12036 return;
12037
12038 Unit const* target = nullptr;
12039 if (victim->GetTypeId() == TYPEID_PLAYER)
12040 target = victim;
12041 else // victim->GetTypeId() == TYPEID_UNIT
12042 {
12043 if (Unit* owner = victim->GetOwner())
12044 if (owner->GetTypeId() == TYPEID_PLAYER)
12045 target = owner;
12046 }
12047
12048 if (!target)
12049 return;
12050
12051 switch (type)
12052 {
12054 // Crit chance reduction works against nonpets
12055 if (crit)
12056 *crit -= target->GetMeleeCritChanceReduction();
12057 if (damage)
12058 {
12059 if (isCrit)
12060 *damage -= target->GetMeleeCritDamageReduction(*damage);
12061 *damage -= target->GetMeleeDamageReduction(*damage);
12062 }
12063 break;
12065 // Crit chance reduction works against nonpets
12066 if (crit)
12067 *crit -= target->GetRangedCritChanceReduction();
12068 if (damage)
12069 {
12070 if (isCrit)
12071 *damage -= target->GetRangedCritDamageReduction(*damage);
12072 *damage -= target->GetRangedDamageReduction(*damage);
12073 }
12074 break;
12076 // Crit chance reduction works against nonpets
12077 if (crit)
12078 *crit -= target->GetSpellCritChanceReduction();
12079 if (damage)
12080 {
12081 if (isCrit)
12082 *damage -= target->GetSpellCritDamageReduction(*damage);
12083 *damage -= target->GetSpellDamageReduction(*damage);
12084 }
12085 break;
12086 default:
12087 break;
12088 }
12089}
12090
12091int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const& casterGuid) const
12092{
12093 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
12094 if (casterGuid.IsAnyTypeCreature())
12096
12097 return damage;
12098}
12099
12100// Melee based spells can be miss, parry or dodge on this step
12101// Crit or block - determined on damage calculation phase! (and can be both in some time)
12102float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
12103{
12104 SpellInfo const* spellInfo = spellId ? sSpellMgr->GetSpellInfo(spellId) : nullptr;
12105 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_CANT_MISS))
12106 return 0.f;
12107
12108 //calculate miss chance
12109 float missChance = victim->GetUnitMissChance();
12110
12111 // Check if dual wielding, add additional miss penalty - when mainhand has on next swing spell, offhand doesnt suffer penalty
12112 if (!spellId && haveOffhandWeapon() && attType != RANGED_ATTACK && !m_currentSpells[CURRENT_MELEE_SPELL])
12113 missChance += 19.0f;
12114
12115 // bonus from skills is 0.04%
12116 //miss_chance -= skillDiff * 0.04f;
12117 int32 diff = -skillDiff;
12118 if (victim->GetTypeId() == TYPEID_PLAYER)
12119 missChance += diff > 0 ? diff * 0.04f : diff * 0.02f;
12120 else
12121 {
12122 missChance += diff > 10 ? 1 + (diff - 10) * 0.4f : diff * 0.1f;
12123 float levelFactor = victim->GetLevelForTarget(this);
12124 if (levelFactor < 10.f)
12125 missChance *= (levelFactor / 10.f);
12126 }
12127
12128 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
12129 float resistMissChance = 100.0f;
12130 if (spellId)
12131 {
12132 if (Player* modOwner = GetSpellModOwner())
12133 modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, resistMissChance);
12134 }
12135 missChance -= resistMissChance - 100.0f;
12136
12137 if (attType == RANGED_ATTACK)
12138 missChance -= m_modRangedHitChance;
12139 else
12140 missChance -= m_modMeleeHitChance;
12141
12142 // miss chance from auras after calculating skill based miss
12144 if (attType == RANGED_ATTACK)
12146 else
12148
12149 return std::max(missChance, 0.f);
12150}
12151
12152void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
12153{
12154 if (newPhaseMask == GetPhaseMask())
12155 return;
12156
12157 // Phase player, dont update
12158 WorldObject::SetPhaseMask(newPhaseMask, false);
12159
12160 // Phase pets and summons
12161 if (IsInWorld())
12162 {
12163 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
12164 if ((*itr)->GetTypeId() == TYPEID_UNIT)
12165 (*itr)->SetPhaseMask(newPhaseMask, true);
12166
12167 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
12168 if (!m_SummonSlot[i].IsEmpty())
12169 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
12170 summon->SetPhaseMask(newPhaseMask, true);
12171
12172 RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target
12173 }
12174
12175 // Update visibility after phasing pets and summons so they wont despawn
12176 if (update)
12178}
12179
12181{
12182 if (!forced)
12184 else
12185 {
12187 // call MoveInLineOfSight for nearby creatures
12188 Trinity::AIRelocationNotifier notifier(*this);
12189 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
12190 }
12191}
12192
12193void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
12194{
12195 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8 + 4 + 4 + 4 + 4 + 4));
12196 data << GetPackGUID();
12197 data << uint32(0); // counter
12198 data << TaggedPosition<Position::XY>(vcos, vsin);
12199 data << float(speedXY); // Horizontal speed
12200 data << float(speedZ); // Z Movement speed (vertical)
12201 player->SendDirectMessage(&data);
12202}
12203
12204void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
12205{
12206 if (IsMovedByServer())
12207 {
12208 GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ);
12209 }
12210 else
12211 {
12212 float vcos, vsin;
12213 GetSinCos(x, y, vsin, vcos);
12214 SendMoveKnockBack(GetGameClientMovingMe()->GetBasePlayer(), speedXY, -speedZ, vcos, vsin);
12215
12217 SetCanFly(true, true);
12218 }
12219}
12220
12222{
12223 if (Player const* player = ToPlayer())
12224 return player->GetRatingBonusValue(cr);
12225 // Player's pet get resilience from owner
12226 else if (IsPet() && GetOwner())
12227 if (Player* owner = GetOwner()->ToPlayer())
12228 return owner->GetRatingBonusValue(cr);
12229
12230 return 0.0f;
12231}
12232
12233uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
12234{
12235 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
12236 return CalculatePct(damage, percent);
12237}
12238
12240{
12241 // Hardcoded cases
12242 switch (spellId)
12243 {
12244 case 7090: // Bear Form
12245 return 29414;
12246 case 35200: // Roc Form
12247 return 4877;
12248 default:
12249 break;
12250 }
12251
12252 if (Player const* player = ToPlayer())
12253 {
12254 switch (form)
12255 {
12256 case FORM_CAT:
12257 // Based on Hair color
12258 if (GetRace() == RACE_NIGHTELF)
12259 {
12260 switch (player->GetHairColorId())
12261 {
12262 case 7: // Violet
12263 case 8:
12264 return 29405;
12265 case 3: // Light Blue
12266 return 29406;
12267 case 0: // Green
12268 case 1: // Light Green
12269 case 2: // Dark Green
12270 return 29407;
12271 case 4: // White
12272 return 29408;
12273 default: // original - Dark Blue
12274 return 892;
12275 }
12276 }
12277 // Based on Skin color
12278 else if (GetRace() == RACE_TAUREN)
12279 {
12280 uint8 skinColor = player->GetSkinId();
12281 // Male
12283 {
12284 switch (skinColor)
12285 {
12286 case 12: // White
12287 case 13:
12288 case 14:
12289 case 18: // Completly White
12290 return 29409;
12291 case 9: // Light Brown
12292 case 10:
12293 case 11:
12294 return 29410;
12295 case 6: // Brown
12296 case 7:
12297 case 8:
12298 return 29411;
12299 case 0: // Dark
12300 case 1:
12301 case 2:
12302 case 3: // Dark Grey
12303 case 4:
12304 case 5:
12305 return 29412;
12306 default: // original - Grey
12307 return 8571;
12308 }
12309 }
12310 // Female
12311 else
12312 {
12313 switch (skinColor)
12314 {
12315 case 10: // White
12316 return 29409;
12317 case 6: // Light Brown
12318 case 7:
12319 return 29410;
12320 case 4: // Brown
12321 case 5:
12322 return 29411;
12323 case 0: // Dark
12324 case 1:
12325 case 2:
12326 case 3:
12327 return 29412;
12328 default: // original - Grey
12329 return 8571;
12330 }
12331 }
12332 }
12333 else if (Player::TeamForRace(GetRace()) == ALLIANCE)
12334 return 892;
12335 else
12336 return 8571;
12337 case FORM_DIREBEAR:
12338 case FORM_BEAR:
12339 // Based on Hair color
12340 if (GetRace() == RACE_NIGHTELF)
12341 {
12342 switch (player->GetHairColorId())
12343 {
12344 case 0: // Green
12345 case 1: // Light Green
12346 case 2: // Dark Green
12347 return 29413; // 29415?
12348 case 6: // Dark Blue
12349 return 29414;
12350 case 4: // White
12351 return 29416;
12352 case 3: // Light Blue
12353 return 29417;
12354 default: // original - Violet
12355 return 2281;
12356 }
12357 }
12358 // Based on Skin color
12359 else if (GetRace() == RACE_TAUREN)
12360 {
12361 uint8 skinColor = player->GetSkinId();
12362 // Male
12364 {
12365 switch (skinColor)
12366 {
12367 case 0: // Dark (Black)
12368 case 1:
12369 case 2:
12370 return 29418;
12371 case 3: // White
12372 case 4:
12373 case 5:
12374 case 12:
12375 case 13:
12376 case 14:
12377 return 29419;
12378 case 9: // Light Brown/Grey
12379 case 10:
12380 case 11:
12381 case 15:
12382 case 16:
12383 case 17:
12384 return 29420;
12385 case 18: // Completly White
12386 return 29421;
12387 default: // original - Brown
12388 return 2289;
12389 }
12390 }
12391 // Female
12392 else
12393 {
12394 switch (skinColor)
12395 {
12396 case 0: // Dark (Black)
12397 case 1:
12398 return 29418;
12399 case 2: // White
12400 case 3:
12401 return 29419;
12402 case 6: // Light Brown/Grey
12403 case 7:
12404 case 8:
12405 case 9:
12406 return 29420;
12407 case 10: // Completly White
12408 return 29421;
12409 default: // original - Brown
12410 return 2289;
12411 }
12412 }
12413 }
12414 else if (Player::TeamForRace(GetRace()) == ALLIANCE)
12415 return 2281;
12416 else
12417 return 2289;
12418 case FORM_FLIGHT:
12420 return 20857;
12421 return 20872;
12422 case FORM_FLIGHT_EPIC:
12424 return 21243;
12425 return 21244;
12426 default:
12427 break;
12428 }
12429 }
12430
12431 uint32 modelid = 0;
12432 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
12433 if (formEntry && formEntry->CreatureDisplayID[0])
12434 {
12435 // Take the alliance modelid as default
12436 if (GetTypeId() != TYPEID_PLAYER)
12437 return formEntry->CreatureDisplayID[0];
12438 else
12439 {
12441 modelid = formEntry->CreatureDisplayID[0];
12442 else
12443 modelid = formEntry->CreatureDisplayID[1];
12444
12445 // If the player is horde but there are no values for the horde modelid - take the alliance modelid
12446 if (!modelid && Player::TeamForRace(GetRace()) == HORDE)
12447 modelid = formEntry->CreatureDisplayID[0];
12448 }
12449 }
12450
12451 return modelid;
12452}
12453
12454void Unit::JumpTo(float speedXY, float speedZ, bool forward, Optional<Position> dest)
12455{
12456 float angle = forward ? 0 : float(M_PI);
12457 if (dest)
12458 angle += GetRelativeAngle(*dest);
12459
12460 if (GetTypeId() == TYPEID_UNIT)
12461 GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ);
12462 else
12463 {
12464 float vcos = std::cos(angle+GetOrientation());
12465 float vsin = std::sin(angle+GetOrientation());
12466 SendMoveKnockBack(ToPlayer(), speedXY, -speedZ, vcos, vsin);
12467 }
12468}
12469
12470void Unit::JumpTo(WorldObject* obj, float speedZ, bool withOrientation)
12471{
12472 float x, y, z;
12473 obj->GetContactPoint(this, x, y, z);
12474 float speedXY = GetExactDist2d(x, y) * 10.0f / speedZ;
12475 GetMotionMaster()->MoveJump(x, y, z, GetAbsoluteAngle(obj), speedXY, speedZ, EVENT_JUMP, withOrientation);
12476}
12477
12478void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12479{
12480 bool spellClickHandled = false;
12481 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12483
12484 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12485 for (auto const& clickPair : clickBounds)
12486 {
12488 if (!clickPair.second.IsFitToRequirements(clicker, this))
12489 continue;
12490
12492 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12493 continue;
12494
12495 Unit* caster = (clickPair.second.castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12496 Unit* target = (clickPair.second.castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12497 ObjectGuid origCasterGUID = (clickPair.second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12498
12499 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(clickPair.second.spellId);
12500 // if (!spellEntry) should be checked at npc_spellclick load
12501
12502 if (seatId > -1)
12503 {
12504 uint8 i = 0;
12505 bool valid = false;
12506 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12507 {
12508 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12509 {
12510 valid = true;
12511 break;
12512 }
12513 ++i;
12514 }
12515
12516 if (!valid)
12517 {
12518 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", clickPair.second.spellId);
12519 continue;
12520 }
12521
12522 if (IsInMap(caster))
12523 {
12525 args.OriginalCaster = origCasterGUID;
12526 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1);
12527 caster->CastSpell(target, clickPair.second.spellId, args);
12528 }
12529 else // This can happen during Player::_LoadAuras
12530 {
12531 int32 bp[MAX_SPELL_EFFECTS] = { };
12532 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12533 bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
12534
12535 bp[i] = seatId;
12536
12537 AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this);
12538 createInfo
12539 .SetCaster(clicker)
12540 .SetBaseAmount(bp)
12541 .SetCasterGUID(origCasterGUID);
12542
12544 }
12545 }
12546 else
12547 {
12548 if (IsInMap(caster))
12549 caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12550 else
12551 {
12552 AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this);
12553 createInfo
12554 .SetCaster(clicker)
12555 .SetCasterGUID(origCasterGUID);
12556
12558 }
12559 }
12560
12561 spellClickHandled = true;
12562 }
12563
12564 Creature* creature = ToCreature();
12565 if (creature && creature->IsAIEnabled())
12566 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12567}
12568
12569void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12570{
12572 args.AddSpellBP0(seatId + 1);
12574}
12575
12576void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12577{
12578 // Must be called only from aura handler
12579 ASSERT(aurApp);
12580
12581 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12582 return;
12583
12584 if (m_vehicle)
12585 {
12586 if (m_vehicle != vehicle)
12587 {
12588 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12589 ExitVehicle();
12590 }
12591 else if (seatId >= 0 && seatId == GetTransSeat())
12592 return;
12593 else
12594 {
12595 //Exit the current vehicle because unit will reenter in a new seat.
12597 }
12598 }
12599
12600 if (aurApp->GetRemoveMode())
12601 return;
12602
12603 if (Player* player = ToPlayer())
12604 {
12605 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12606 {
12607 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12608 return;
12609 }
12610
12611 if (Creature* vehicleBaseCreature = vehicle->GetBase()->ToCreature())
12612 {
12613 // If a player entered a vehicle that is part of a formation, remove it from said formation
12614 if (CreatureGroup* creatureGroup = vehicleBaseCreature->GetFormation())
12615 sFormationMgr->RemoveCreatureFromGroup(creatureGroup, vehicleBaseCreature);
12616 }
12617 }
12618
12619 // If vehicle flag for fixed position set (cannons), or if the following hardcoded units, then set state rooted
12620 // 30236 | Argent Cannon
12621 // 39759 | Tankbuster Cannon
12622 if ((vehicle->GetVehicleInfo()->Flags & VEHICLE_FLAG_FIXED_POSITION) || vehicle->GetBase()->GetEntry() == 30236 || vehicle->GetBase()->GetEntry() == 39759)
12624
12625 ASSERT(!m_vehicle);
12626 (void)vehicle->AddPassenger(this, seatId);
12627}
12628
12629void Unit::ChangeSeat(int8 seatId, bool next)
12630{
12631 if (!m_vehicle)
12632 return;
12633
12634 // Don't change if current and new seat are identical
12635 if (seatId == GetTransSeat())
12636 return;
12637
12638 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12639 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12640 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12641 return;
12642
12643 AuraEffect* rideVehicleEffect = nullptr;
12645 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12646 {
12647 if ((*itr)->GetCasterGUID() != GetGUID())
12648 continue;
12649
12650 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12651 ASSERT(!rideVehicleEffect);
12652 rideVehicleEffect = *itr;
12653 }
12654
12655 // Unit riding a vehicle must always have control vehicle aura on target
12656 ASSERT(rideVehicleEffect);
12657
12658 rideVehicleEffect->ChangeAmount(seat->first + 1);
12659}
12660
12661void Unit::ExitVehicle(Position const* /*exitPosition*/)
12662{
12664 if (!m_vehicle)
12665 return;
12666
12671 /*_ExitVehicle(exitPosition);*/
12678}
12679
12680void Unit::_ExitVehicle(Position const* exitPosition)
12681{
12685 if (!m_vehicle)
12686 return;
12687
12688 // This should be done before dismiss, because there may be some aura removal
12690 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12691
12692 if (!vehicle)
12693 {
12694 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12695 return;
12696 }
12697
12698 Player* player = ToPlayer();
12699
12700 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12701 if (player && player->duel && player->duel->IsMounted)
12702 player->DuelComplete(DUEL_FLED);
12703
12704 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12705
12707
12708 if (player)
12709 player->SetFallInformation(0, GetPositionZ());
12711 {
12713 data << GetPackGUID();
12714 SendMessageToSet(&data, false);
12715 }
12716
12717 Position pos;
12718 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12719 if (exitPosition)
12720 pos = *exitPosition;
12721 else
12722 {
12723 // Set exit position to vehicle position and use the current orientation
12724 pos = vehicle->GetBase()->GetPosition();
12726
12727 // Change exit position based on seat entry addon data
12728 if (seatAddon)
12729 {
12731 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12733 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12734 }
12735 }
12736
12737 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
12738 {
12739 float height = pos.GetPositionZ() + vehicleCollisionHeight;
12740
12741 // Creatures without inhabit type air should begin falling after exiting the vehicle
12742 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
12743 init.SetFall();
12744
12745 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
12746 init.SetFacing(pos.GetOrientation());
12747 init.SetTransportExit();
12748 };
12750
12751 if (player)
12753
12754 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12755 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
12756 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
12757
12759 {
12760 // Vehicle just died, we die too
12761 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
12763 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
12764 else
12765 ToTempSummon()->UnSummon(2000); // Approximation
12766 }
12767}
12768
12773
12774void Unit::BuildMovementPacket(Position const& pos, Position const& transportPos, MovementInfo const& movementInfo, ByteBuffer* data)
12775{
12776 *data << uint32(movementInfo.GetMovementFlags());
12777 *data << uint16(movementInfo.GetExtraMovementFlags());
12778 *data << uint32(GameTime::GetGameTimeMS()); // time / counter
12779 *data << TaggedPosition<Position::XYZO>(pos);
12780
12781 // 0x00000200
12782 if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
12783 {
12784 *data << movementInfo.transport.guid.WriteAsPacked();
12785 *data << TaggedPosition<Position::XYZO>(transportPos);
12786 *data << uint32(movementInfo.transport.time);
12787 *data << int8(movementInfo.transport.seat);
12788
12790 *data << uint32(movementInfo.transport.time2);
12791 }
12792
12793 // 0x02200000
12795 *data << float(movementInfo.pitch);
12796
12797 *data << uint32(movementInfo.fallTime);
12798
12799 // 0x00001000
12800 if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING))
12801 {
12802 *data << float(movementInfo.jump.zspeed);
12803 *data << float(movementInfo.jump.sinAngle);
12804 *data << float(movementInfo.jump.cosAngle);
12805 *data << float(movementInfo.jump.xyspeed);
12806 }
12807
12808 // 0x04000000
12810 *data << float(movementInfo.splineElevation);
12811}
12812
12817
12818bool Unit::CanSwim() const
12819{
12820 // Mirror client behavior, if this method returns false then client will not use swimming animation and for players will apply gravity as if there was no water
12822 return false;
12823 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
12824 return true;
12826 return false;
12828 return true;
12830}
12831
12832void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
12833{
12834 if (Player* player = ToPlayer())
12835 {
12836 WorldLocation target(GetMapId(), pos);
12837 player->TeleportTo(target, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | (casting ? TELE_TO_SPELL : 0));
12838 }
12839 else
12840 {
12841 DisableSpline();
12843 SendTeleportPacket(pos);
12844 UpdatePosition(pos, true);
12846 }
12847}
12848
12849void Unit::SendTeleportPacket(Position const& pos, bool teleportingTransport /*= false*/)
12850{
12851 // MSG_MOVE_TELEPORT is sent to nearby players to signal the teleport
12852 // MSG_MOVE_TELEPORT_ACK is sent to self in order to trigger ACK and update the position server side
12853
12854 MovementInfo teleportMovementInfo = m_movementInfo;
12855 teleportMovementInfo.pos.Relocate(pos);
12856 Position transportPos = m_movementInfo.transport.pos;
12857 if (TransportBase* transportBase = GetDirectTransport())
12858 {
12859 // if its the transport that is teleported then we have old transport position here and cannot use it to calculate offsets
12860 // assume that both transport teleport and teleport within transport cannot happen at the same time
12861 if (!teleportingTransport)
12862 {
12863 float x, y, z, o;
12864 pos.GetPosition(x, y, z, o);
12865 transportBase->CalculatePassengerOffset(x, y, z, &o);
12866 transportPos.Relocate(x, y, z, o);
12867 }
12868 }
12869
12870 WorldPacket moveUpdateTeleport(MSG_MOVE_TELEPORT, 38);
12871 moveUpdateTeleport << GetPackGUID();
12872 Unit::BuildMovementPacket(pos, transportPos, teleportMovementInfo, &moveUpdateTeleport);
12873
12874 if (IsMovedByClient())
12875 {
12876 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
12877 WorldPacket moveTeleport(MSG_MOVE_TELEPORT_ACK, 41);
12878 moveTeleport << GetPackGUID();
12879 moveTeleport << uint32(0); // this value increments every time
12880 Unit::BuildMovementPacket(pos, transportPos, teleportMovementInfo, &moveTeleport);
12881 playerMover->SendDirectMessage(&moveTeleport);
12882
12883 // Broadcast the packet to everyone except self.
12884 SendMessageToSet(&moveUpdateTeleport, playerMover);
12885 }
12886 else
12887 SendMessageToSet(&moveUpdateTeleport, true);
12888}
12889
12890bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
12891{
12892 // prevent crash when a bad coord is sent by the client
12893 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
12894 {
12895 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
12896 return false;
12897 }
12898
12899 // Check if angular distance changed
12900 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
12901
12902 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
12903 bool const relocated = (teleport ||
12904 std::fabs(GetPositionX() - x) > 0.001f ||
12905 std::fabs(GetPositionY() - y) > 0.001f ||
12906 std::fabs(GetPositionZ() - z) > 0.001f);
12907
12908 if (relocated)
12909 {
12910 // move and update visible state if need
12911 if (GetTypeId() == TYPEID_PLAYER)
12912 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
12913 else
12914 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
12915 }
12916 else if (turn)
12917 UpdateOrientation(orientation);
12918
12920
12921 _positionUpdateInfo.Relocated = relocated;
12923
12924 return (relocated || turn);
12925}
12926
12927bool Unit::UpdatePosition(Position const& pos, bool teleport)
12928{
12929 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
12930}
12931
12933void Unit::UpdateOrientation(float orientation)
12934{
12935 SetOrientation(orientation);
12936 if (IsVehicle())
12938}
12939
12941void Unit::UpdateHeight(float newZ)
12942{
12944 if (IsVehicle())
12946}
12947
12952
12959
12961{
12962 m_pendingMovementChanges.emplace_back(std::move(newChange));
12963}
12964
12966{
12967 return std::find_if(m_pendingMovementChanges.begin(), m_pendingMovementChanges.end(),
12968 [changeType](PlayerMovementPendingChange const& pendingChange)
12969 {
12970 return pendingChange.movementChangeType == changeType;
12971 }) != m_pendingMovementChanges.end();
12972}
12973
12975{
12976 if (sWorld->getIntConfig(CONFIG_PENDING_MOVE_CHANGES_TIMEOUT) == 0)
12977 return;
12978
12980 return;
12981
12982 PlayerMovementPendingChange const& oldestChangeToAck = m_pendingMovementChanges.front();
12983 if (GameTime::GetGameTimeMS() > oldestChangeToAck.time + sWorld->getIntConfig(CONFIG_PENDING_MOVE_CHANGES_TIMEOUT))
12984 {
12985 /*
12986 when players are teleported from one corner of a map to an other (example: from Dragonblight to the entrance of Naxxramas, both in the same map: Northend),
12987 is it done through what is called a 'near' teleport. A near teleport always involve teleporting a player from one point to an other in the same map, even if
12988 the distance is huge. When that distance is big enough, a loading screen appears on the client side. During that time, the client loads the surrounding zone
12989 of the new location (and everything it contains). The problem is that, as long as the client hasn't finished loading the new zone, it will NOT ack the near
12990 teleport. So if the server sends a near teleport order at a certain time and the client takes 20s to load the new zone (let's imagine a very slow computer),
12991 even with zero latency, the server will receive an ack from the client only after 20s.
12992
12993 For this reason and because the current implementation is simple (you dear reader, feel free to improve it if you can), we will just ignore checking for
12994 near teleport acks (for now. @todo).
12995 */
12996 if (oldestChangeToAck.movementChangeType == MovementChangeType::TELEPORT)
12997 return;
12998
12999 GameClient* controller = GetGameClientMovingMe();
13000 controller->GetWorldSession()->KickPlayer("Took too long to ack a movement change");
13001 TC_LOG_INFO("cheat", "Unit::CheckPendingMovementAcks: Player GUID: {} took too long to acknowledge a movement change. He was therefore kicked.", controller->GetBasePlayer()->GetGUID().ToString());
13002 }
13003}
13004
13005void Unit::PurgeAndApplyPendingMovementChanges(bool informObservers /* = true */)
13006{
13007 for (auto pendingChange = m_pendingMovementChanges.cbegin(); pendingChange != m_pendingMovementChanges.cend(); ++pendingChange)
13008 {
13009 float speedFlat = pendingChange->newValue;
13010 MovementChangeType changeType = pendingChange->movementChangeType;
13011 UnitMoveType moveType;
13012 switch (changeType)
13013 {
13014 case MovementChangeType::SPEED_CHANGE_WALK: moveType = MOVE_WALK; break;
13015 case MovementChangeType::SPEED_CHANGE_RUN: moveType = MOVE_RUN; break;
13017 case MovementChangeType::SPEED_CHANGE_SWIM: moveType = MOVE_SWIM; break;
13023 default:
13024 ASSERT(false);
13025 return;
13026 }
13027
13028 float newSpeedRate = speedFlat / (IsControlledByPlayer() ? playerBaseMoveSpeed[moveType] : baseMoveSpeed[moveType]);
13029 SetSpeedRateReal(moveType, newSpeedRate);
13030
13031 if (informObservers)
13032 MovementPacketSender::SendSpeedChangeToObservers(this, moveType, speedFlat);
13033 }
13034
13036}
13037
13042
13043void Unit::RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker)
13044{
13045 float addRage;
13046
13047 float rageconversion = ((0.0091107836f * GetLevel() * GetLevel()) + 3.225598133f * GetLevel()) + 4.2652911f;
13048
13049 // Unknown if correct, but lineary adjust rage conversion above level 70
13050 if (GetLevel() > 70)
13051 rageconversion += 13.27f * (GetLevel() - 70);
13052
13053 if (attacker)
13054 {
13055 addRage = (damage / rageconversion * 7.5f + weaponSpeedHitFactor) / 2;
13056
13057 // talent who gave more rage on attack
13059 }
13060 else
13061 {
13062 addRage = damage / rageconversion * 2.5f;
13063
13064 // Berserker Rage effect
13065 if (HasAura(18499))
13066 addRage *= 2.0f;
13067 }
13068
13069 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
13070
13071 ModifyPower(POWER_RAGE, uint32(addRage * 10));
13072}
13073
13075{
13076 if (Unit* victim = GetVictim())
13077 {
13078 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
13079 {
13080 AttackStop();
13081 if (IsNonMeleeSpellCast(false))
13083
13084 // melee and ranged forced attack cancel
13085 if (GetTypeId() == TYPEID_PLAYER)
13087 }
13088 }
13089
13090 AttackerSet const& attackers = getAttackers();
13091 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
13092 {
13093 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
13094 {
13095 (*itr)->AttackStop();
13096 itr = attackers.begin();
13097 }
13098 else
13099 ++itr;
13100 }
13101
13102 std::vector<CombatReference*> refsToEnd;
13103 for (auto const& pair : m_combatManager.GetPvECombatRefs())
13104 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
13105 refsToEnd.push_back(pair.second);
13106 for (CombatReference* ref : refsToEnd)
13107 ref->EndCombat();
13108
13109 for (Unit* minion : m_Controlled)
13110 minion->StopAttackFaction(faction_id);
13111}
13112
13114{
13115 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
13116 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
13117 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
13118 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
13119 if (IsInWorld())
13120 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
13121
13122 std::ostringstream o;
13123 o << "Summon Slot: ";
13124 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
13125 o << m_SummonSlot[i].ToString() << ", ";
13126
13127 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13128 o.str("");
13129
13130 o << "Controlled List: ";
13131 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
13132 o << (*itr)->GetGUID().ToString() << ", ";
13133 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13134 o.str("");
13135
13136 o << "Aura List: ";
13137 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
13138 o << itr->first << ", ";
13139 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13140 o.str("");
13141
13142 if (IsVehicle())
13143 {
13144 o << "Passenger List: ";
13145 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
13146 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
13147 o << passenger->GetGUID().ToString() << ", ";
13148 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13149 }
13150
13151 if (GetVehicle())
13152 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
13153}
13154
13156{
13158 data << GetPackGUID();
13159 SendMessageToSet(&data, false);
13160}
13161
13163{
13164 int32 resist = -1;
13165 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
13166 if (mask & (1 << i) && (resist < 0 || resist > int32(GetResistance(SpellSchools(i)))))
13167 resist = int32(GetResistance(SpellSchools(i)));
13168
13169 // resist value will never be negative here
13170 return resist;
13171}
13172
13174{
13175 _isCommandAttack = val;
13176}
13177
13179{
13180 return _isCommandAttack;
13181}
13182
13184{
13185 _isCommandFollow = val;
13186}
13187
13189{
13190 return _isCommandFollow;
13191}
13192
13194{
13196 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
13197
13199 if (TransportBase* transport = _unit->GetDirectTransport())
13200 transport->CalculatePassengerPosition(stayPos.x, stayPos.y, stayPos.z);
13201
13202 _stayX = stayPos.x;
13203 _stayY = stayPos.y;
13204 _stayZ = stayPos.z;
13205}
13206
13207void CharmInfo::GetStayPosition(float &x, float &y, float &z)
13208{
13209 x = _stayX;
13210 y = _stayY;
13211 z = _stayZ;
13212}
13213
13215{
13216 _isAtStay = val;
13217}
13218
13220{
13221 return _isAtStay;
13222}
13223
13225{
13226 _isFollowing = val;
13227}
13228
13230{
13231 return _isFollowing;
13232}
13233
13235{
13236 _isReturning = val;
13237}
13238
13240{
13241 return _isReturning;
13242}
13243
13245{
13248}
13249
13250void Unit::SetFacingTo(float ori, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13251{
13252 // do not face when already moving
13253 if (!force && (!IsStopped() || !movespline->Finalized()))
13254 return;
13255
13256 GetMotionMaster()->MoveFace(ori, movementId);
13257}
13258
13259void Unit::SetFacingToObject(WorldObject const* object, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13260{
13261 // do not face when already moving
13262 if (!force && (!IsStopped() || !movespline->Finalized()))
13263 return;
13264
13265 GetMotionMaster()->MoveFace(object, movementId);
13266}
13267
13268bool Unit::SetWalk(bool enable)
13269{
13270 if (enable == IsWalking())
13271 return false;
13272
13273 if (enable)
13275 else
13277
13279
13280 WorldPacket data(walkModeTable[enable], 9);
13281 data << GetPackGUID();
13282 SendMessageToSet(&data, true);
13283 return true;
13284}
13285
13286bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/)
13287{
13288 if (disable == IsGravityDisabled())
13289 return false;
13290
13291 if (disable)
13292 {
13295 }
13296 else
13298
13299 static OpcodeServer const gravityOpcodeTable[2][2] =
13300 {
13303 };
13304
13305 if (IsMovedByClient())
13306 {
13307 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13308
13309 WorldPacket data(gravityOpcodeTable[disable][1], 12);
13310 data << GetPackGUID();
13311 data << uint32(0);
13312 playerMover->SendDirectMessage(&data);
13313
13315 data << GetPackGUID();
13316 BuildMovementPacket(&data);
13317 SendMessageToSet(&data, playerMover);
13318 }
13319 else
13320 {
13321 WorldPacket data(gravityOpcodeTable[disable][0], 9);
13322 data << GetPackGUID();
13323 SendMessageToSet(&data, true);
13324 }
13325
13326 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->GetMovementTemplate().IsRooted())
13327 {
13328 if (IsGravityDisabled())
13330 else if (IsHovering())
13332 else
13334 }
13335
13336 return true;
13337}
13338
13339bool Unit::SetFall(bool enable)
13340{
13342 return false;
13343
13344 if (enable)
13345 {
13348 }
13349 else
13351
13352 return true;
13353}
13354
13355bool Unit::SetSwim(bool enable)
13356{
13358 return false;
13359
13360 if (enable)
13362 else
13364
13365 static OpcodeServer const swimOpcodeTable[2] = { SMSG_SPLINE_MOVE_STOP_SWIM, SMSG_SPLINE_MOVE_START_SWIM };
13366
13367 WorldPacket data(swimOpcodeTable[enable], 9);
13368 data << GetPackGUID();
13369 SendMessageToSet(&data, true);
13370
13371 return true;
13372}
13373
13374bool Unit::SetCanFly(bool enable, bool packetOnly /*= false */)
13375{
13376 if (!packetOnly)
13377 {
13379 return false;
13380
13381 if (enable)
13382 {
13385 }
13386 else
13388 }
13389
13390 static OpcodeServer const flyOpcodeTable[2][2] =
13391 {
13394 };
13395
13396 if (!enable && GetTypeId() == TYPEID_PLAYER)
13398
13399 if (IsMovedByClient())
13400 {
13401 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13402
13403 WorldPacket data(flyOpcodeTable[enable][1], 12);
13404 data << GetPackGUID();
13405 data << uint32(0);
13406 playerMover->SendDirectMessage(&data);
13407
13409 data << GetPackGUID();
13410 BuildMovementPacket(&data);
13411 SendMessageToSet(&data, playerMover);
13412 }
13413 else
13414 {
13415 WorldPacket data(flyOpcodeTable[enable][0], 9);
13416 data << GetPackGUID();
13417 SendMessageToSet(&data, true);
13418 }
13419
13420 return true;
13421}
13422
13423bool Unit::SetWaterWalking(bool enable)
13424{
13426 return false;
13427
13428 if (enable)
13430 else
13432
13433 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
13434 {
13437 };
13438
13439 if (IsMovedByClient())
13440 {
13441 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13442
13443 WorldPacket data(waterWalkingOpcodeTable[enable][1], 12);
13444 data << GetPackGUID();
13445 data << uint32(0);
13447
13449 data << GetPackGUID();
13450 BuildMovementPacket(&data);
13451 SendMessageToSet(&data, playerMover);
13452 }
13453 else
13454 {
13455 WorldPacket data(waterWalkingOpcodeTable[enable][0], 9);
13456 data << GetPackGUID();
13457 SendMessageToSet(&data, true);
13458 }
13459
13460 return true;
13461}
13462
13463bool Unit::SetFeatherFall(bool enable)
13464{
13466 return false;
13467
13468 if (enable)
13470 else
13472
13473 static OpcodeServer const featherFallOpcodeTable[2][2] =
13474 {
13477 };
13478
13479 if (IsMovedByClient())
13480 {
13481 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13482
13483 WorldPacket data(featherFallOpcodeTable[enable][1], 12);
13484 data << GetPackGUID();
13485 data << uint32(0);
13486 playerMover->SendDirectMessage(&data);
13487
13489 data << GetPackGUID();
13490 BuildMovementPacket(&data);
13491 SendMessageToSet(&data, playerMover);
13492 }
13493 else
13494 {
13495 WorldPacket data(featherFallOpcodeTable[enable][0], 9);
13496 data << GetPackGUID();
13497 SendMessageToSet(&data, true);
13498 }
13499
13500 return true;
13501}
13502
13503bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
13504{
13506 return false;
13507
13508 float hoverHeight = GetFloatValue(UNIT_FIELD_HOVERHEIGHT);
13509
13510 if (enable)
13511 {
13514 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
13515 UpdateHeight(std::max(GetFloorZ() + hoverHeight, GetPositionZ()));
13516 }
13517 else
13518 {
13521 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
13522 {
13523 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
13525 UpdateHeight(newZ);
13526 }
13527 }
13528
13529 static OpcodeServer const hoverOpcodeTable[2][2] =
13530 {
13533 };
13534
13535 if (IsMovedByClient())
13536 {
13537 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13538
13539 WorldPacket data(hoverOpcodeTable[enable][1], 12);
13540 data << GetPackGUID();
13541 data << uint32(0);
13542 playerMover->SendDirectMessage(&data);
13543
13544 data.Initialize(MSG_MOVE_HOVER, 64);
13545 data << GetPackGUID();
13546 BuildMovementPacket(&data);
13547 SendMessageToSet(&data, playerMover);
13548 }
13549 else
13550 {
13551 WorldPacket data(hoverOpcodeTable[enable][0], 9);
13552 data << GetPackGUID();
13553 SendMessageToSet(&data, true);
13554 }
13555
13556 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->GetMovementTemplate().IsRooted())
13557 {
13558 if (IsGravityDisabled())
13560 else if (IsHovering())
13562 else
13564 }
13565
13566 return true;
13567}
13568
13570{
13571 return movespline->Initialized() && !movespline->Finalized();
13572}
13573
13574void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player const* target) const
13575{
13576 if (!target)
13577 return;
13578
13579 ByteBuffer fieldBuffer;
13580
13582
13584 uint32 visibleFlag = UF_FLAG_PUBLIC;
13585
13586 if (target == this)
13587 visibleFlag |= UF_FLAG_PRIVATE;
13588
13590 if (GetOwnerGUID() == target->GetGUID())
13591 visibleFlag |= UF_FLAG_OWNER;
13592
13595 visibleFlag |= UF_FLAG_SPECIAL_INFO;
13596
13597 if (plr && plr->IsInSameRaidWith(target))
13598 visibleFlag |= UF_FLAG_PARTY_MEMBER;
13599
13600 Creature const* creature = ToCreature();
13601 for (uint16 index = 0; index < m_valuesCount; ++index)
13602 {
13603 if (_fieldNotifyFlags & flags[index] ||
13604 ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) ||
13605 ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)) ||
13607 {
13608 updateMask.SetBit(index);
13609
13610 if (index == UNIT_NPC_FLAGS)
13611 {
13612 uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS];
13613
13614 if (creature)
13615 if (!target->CanSeeSpellClickOn(creature))
13616 appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
13617
13618 fieldBuffer << uint32(appendValue);
13619 }
13620 else if (index == UNIT_FIELD_AURASTATE)
13621 {
13622 // Check per caster aura states to not enable using a spell in client if specified aura is not by target
13623 fieldBuffer << BuildAuraStateUpdateForTarget(target);
13624 }
13625 // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
13626 else if (index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
13627 {
13628 // convert from float to uint32 and send
13629 fieldBuffer << uint32(m_floatValues[index] < 0 ? 0 : m_floatValues[index]);
13630 }
13631 // there are some float values which may be negative or can't get negative due to other checks
13632 else if ((index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4) ||
13635 (index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4))
13636 {
13637 fieldBuffer << uint32(m_floatValues[index]);
13638 }
13639 // Gamemasters should be always able to interact with units - remove uninteractible flag
13640 else if (index == UNIT_FIELD_FLAGS)
13641 {
13642 uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS];
13643 if (target->IsGameMaster())
13644 appendValue &= ~UNIT_FLAG_UNINTERACTIBLE;
13645
13646 fieldBuffer << uint32(appendValue);
13647 }
13648 // use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
13649 else if (index == UNIT_FIELD_DISPLAYID)
13650 {
13652 if (creature)
13653 {
13654 CreatureTemplate const* cinfo = creature->GetCreatureTemplate();
13655
13656 // this also applies for transform auras
13657 if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(GetTransformSpell()))
13658 {
13659 for (SpellEffectInfo const& spellEffectInfo : transform->GetEffects())
13660 {
13661 if (spellEffectInfo.IsAura(SPELL_AURA_TRANSFORM))
13662 {
13663 if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(spellEffectInfo.MiscValue))
13664 {
13665 cinfo = transformInfo;
13666 break;
13667 }
13668 }
13669 }
13670 }
13671
13673 if (target->IsGameMaster())
13674 displayId = cinfo->GetFirstVisibleModel();
13675 }
13676
13677 fieldBuffer << uint32(displayId);
13678 }
13679 // hide lootable animation for unallowed players
13680 else if (index == UNIT_DYNAMIC_FLAGS)
13681 {
13683
13684 if (creature)
13685 {
13686 if (creature->hasLootRecipient())
13687 {
13688 dynamicFlags |= UNIT_DYNFLAG_TAPPED;
13689 if (creature->isTappedBy(target))
13690 dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER;
13691 }
13692
13693 if (!target->isAllowedToLoot(creature))
13694 dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE;
13695 }
13696
13697 // unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras
13698 if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT)
13700 dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT;
13701
13702 fieldBuffer << dynamicFlags;
13703 }
13704 // FG: pretend that OTHER players in own group are friendly ("blue")
13705 else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
13706 {
13707 if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
13708 {
13710 FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
13711 if (!ft1->IsFriendlyTo(*ft2))
13712 {
13713 if (index == UNIT_FIELD_BYTES_2)
13714 // Allow targetting opposite faction in party when enabled in config
13715 fieldBuffer << (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8)); // this flag is at uint8 offset 1 !!
13716 else
13717 // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
13718 fieldBuffer << uint32(target->GetFaction());
13719 }
13720 else
13721 fieldBuffer << m_uint32Values[index];
13722 }
13723 else
13724 fieldBuffer << m_uint32Values[index];
13725 }
13726 else
13727 {
13728 // send in current format (float as float, uint32 as uint32)
13729 fieldBuffer << m_uint32Values[index];
13730 }
13731 }
13732 }
13733
13734 updateMask.AppendToPacket(data);
13735 data->append(fieldBuffer);
13736}
13737
13738void Unit::DestroyForPlayer(Player* target, bool onDeath) const
13739{
13740 if (Battleground* bg = target->GetBattleground())
13741 {
13742 if (bg->isArena())
13743 {
13745 destroyArenaUnit.Guid = GetGUID();
13746 target->GetSession()->SendPacket(destroyArenaUnit.Write());
13747 }
13748 }
13749
13750 WorldObject::DestroyForPlayer(target, onDeath);
13751}
13752
13753int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
13754{
13755 int32 val = 0;
13756 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
13757 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
13758 {
13759 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
13760 {
13761 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
13762 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
13763 {
13764 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
13765 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
13766 {
13767 // absolute value only
13768 if (abs(val) < abs((*auraItr)->GetAmount()))
13769 val = (*auraItr)->GetAmount();
13770 }
13771 }
13772 }
13773 }
13774 return val;
13775}
13776
13777bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
13778{
13779 for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
13780 if (AuraEffect const* aurEff = aura->GetEffect(i))
13781 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
13782 return false;
13783
13784 return true;
13785}
13786
13787bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
13788{
13789 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
13790 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
13791 {
13792 AuraEffect const* existingAurEff = (*itr);
13793 ++itr;
13794
13795 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
13796 {
13797 int32 diff = abs(effectAmount) - abs(existingAurEff->GetAmount());
13798 if (!diff)
13799 for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
13800 diff += int32((auraEffectMask & (1 << i)) >> i) - int32((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i);
13801
13802 if (diff > 0)
13803 {
13804 Aura const* base = existingAurEff->GetBase();
13805 // no removing of area auras from the original owner, as that completely cancels them
13806 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
13807 {
13808 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
13809 {
13810 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
13811 uint32 removedAuras = m_removedAurasCount;
13812 RemoveAura(aurApp);
13813 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
13814 itr = auras.begin();
13815 }
13816 }
13817 }
13818 else if (diff < 0)
13819 return false;
13820 }
13821 }
13822
13823 return true;
13824}
13825
13826void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
13827{
13828 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
13831 Cell::VisitWorldObjects(this, worker, textRange);
13832}
13833
13834void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13835{
13836 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13837}
13838
13839void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13840{
13841 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13842}
13843
13844void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13845{
13847}
13848
13849void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
13850{
13851 if (!target)
13852 return;
13853
13855 WorldPacket data;
13856 ChatHandler::BuildChatPacket(data, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
13857 target->SendDirectMessage(&data);
13858}
13859
13861{
13862 if (slot >= MAX_EQUIPMENT_ITEMS)
13863 return 0;
13864
13866}
13867
13869{
13870 if (slot >= MAX_EQUIPMENT_ITEMS)
13871 return;
13872
13874}
13875
13876void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
13877{
13878 if (!sObjectMgr->GetBroadcastText(textId))
13879 {
13880 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
13881 return;
13882 }
13883
13884 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
13887 Cell::VisitWorldObjects(this, worker, textRange);
13888}
13889
13890void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
13891{
13892 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13893}
13894
13895void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
13896{
13897 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13898}
13899
13900void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13901{
13902 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
13903}
13904
13905void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
13906{
13907 if (!target)
13908 return;
13909
13910 BroadcastText const* bct = sObjectMgr->GetBroadcastText(textId);
13911 if (!bct)
13912 {
13913 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterWhisper: `broadcast_text` was not {} found", textId);
13914 return;
13915 }
13916
13918 WorldPacket data;
13919 ChatHandler::BuildChatPacket(data, isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, bct->GetText(locale, GetGender()), 0, "", locale);
13920 target->SendDirectMessage(&data);
13921}
13922
13923// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
13925{
13926 float scaleMod = GetObjectScale(); // 99% sure about this
13927
13928 if (IsMounted())
13929 {
13930 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
13931 {
13932 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
13933 {
13934 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13935 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13936 float const collisionHeight = scaleMod * (mountModelData->MountHeight + modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f);
13937 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13938 }
13939 }
13940 }
13941
13943 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13944 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13945
13946 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
13947 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13948}
13949
13950std::string Unit::GetDebugInfo() const
13951{
13952 std::stringstream sstr;
13953 sstr << WorldObject::GetDebugInfo() << "\n"
13954 << std::boolalpha
13955 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
13956 << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
13957 << " Class: " << std::to_string(GetClass()) << "\n"
13958 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
13959 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
13960 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
13961 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
13962 << "GetGameClientMovingMe(): " << (GetGameClientMovingMe() ? GetGameClientMovingMe()->GetDebugInfo() : "NULL") << "\n"
13963 << "m_Controlled size: " << m_Controlled.size();
13964
13965 size_t controlledCount = 0;
13966 for (Unit* controlled : m_Controlled)
13967 {
13968 ++controlledCount;
13969 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
13970 }
13971
13972 return sstr.str();
13973}
#define sBattlefieldMgr
@ SCORE_DAMAGE_DONE
@ SCORE_HEALING_DONE
#define sCharacterCache
LocaleConstant
Definition Common.h:48
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
@ HOUR
Definition Common.h:30
@ SEC_PLAYER
Definition Common.h:40
@ SEC_GAMEMASTER
Definition Common.h:42
#define M_PI
Definition Common.h:72
#define sConditionMgr
@ CREATURE_FLAG_EXTRA_NO_BLOCK
@ CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS
@ CREATURE_FLAG_EXTRA_NO_CRIT
@ CREATURE_FLAG_EXTRA_TRIGGER
@ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
@ CREATURE_FLAG_EXTRA_INSTANCE_BIND
@ CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
@ CREATURE_FLAG_EXTRA_NO_PARRY
static const uint32 MAX_CREATURE_SPELLS
#define sFormationMgr
#define MAX_EFFECT_MASK
Definition DBCEnums.h:389
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED
Definition DBCEnums.h:222
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST
Definition DBCEnums.h:224
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED
Definition DBCEnums.h:226
@ ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE
Definition DBCEnums.h:181
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED
Definition DBCEnums.h:225
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
Definition DBCEnums.h:150
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_AURA
Definition DBCEnums.h:193
@ ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
Definition DBCEnums.h:142
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED
Definition DBCEnums.h:223
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
Definition DBCEnums.h:149
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT
Definition DBCEnums.h:221
@ ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS
Definition DBCEnums.h:182
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:388
DBCStorage< SpellShapeshiftFormEntry > sSpellShapeshiftFormStore(SpellShapeshiftFormfmt)
DBCStorage< VehicleEntry > sVehicleStore(VehicleEntryfmt)
DBCStorage< PowerDisplayEntry > sPowerDisplayStore(PowerDisplayfmt)
DBCStorage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore(CreatureDisplayInfofmt)
DBCStorage< ChrRacesEntry > sChrRacesStore(ChrRacesEntryfmt)
DBCStorage< CreatureDisplayInfoExtraEntry > sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt)
DBCStorage< CreatureModelDataEntry > sCreatureModelDataStore(CreatureModelDatafmt)
DBCStorage< ChrClassesEntry > sChrClassesStore(ChrClassesEntryfmt)
DBCStorage< LiquidTypeEntry > sLiquidTypeStore(LiquidTypefmt)
@ CHRRACES_FLAGS_CAN_MOUNT
@ CREATURE_MODEL_DATA_FLAGS_CAN_MOUNT
uint8_t uint8
Definition Define.h:135
int16_t int16
Definition Define.h:130
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
uint16 flags
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition Duration.h:36
#define ABORT_MSG
Definition Errors.h:75
#define ASSERT_WITH_SIDE_EFFECTS
Definition Errors.h:72
#define ABORT
Definition Errors.h:74
#define ASSERT_NODEBUGINFO
Definition Errors.h:69
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
@ GROUP_UPDATE_FLAG_CUR_HP
Definition Group.h:102
@ GROUP_UPDATE_FLAG_PET_CUR_HP
Definition Group.h:114
@ GROUP_UPDATE_FLAG_POWER_TYPE
Definition Group.h:104
@ GROUP_UPDATE_FLAG_PET_CUR_POWER
Definition Group.h:117
@ GROUP_UPDATE_FLAG_PET_MAX_POWER
Definition Group.h:118
@ GROUP_UPDATE_FLAG_MAX_HP
Definition Group.h:103
@ GROUP_UPDATE_FLAG_PET_POWER_TYPE
Definition Group.h:116
@ GROUP_UPDATE_FLAG_MAX_POWER
Definition Group.h:106
@ GROUP_UPDATE_FLAG_PET_AURAS
Definition Group.h:119
@ GROUP_UPDATE_FLAG_AURAS
Definition Group.h:110
@ GROUP_UPDATE_FLAG_LEVEL
Definition Group.h:107
@ GROUP_UPDATE_FLAG_PET_MAX_HP
Definition Group.h:115
@ GROUP_UPDATE_FLAG_CUR_POWER
Definition Group.h:105
#define sInstanceSaveMgr
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
@ ITEM_SUBCLASS_WEAPON_GUN
@ ITEM_SUBCLASS_WEAPON_AXE2
@ ITEM_SUBCLASS_WEAPON_STAFF
@ ITEM_SUBCLASS_WEAPON_MACE
@ ITEM_SUBCLASS_WEAPON_EXOTIC2
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
@ ITEM_SUBCLASS_WEAPON_MACE2
@ ITEM_SUBCLASS_WEAPON_DAGGER
@ ITEM_SUBCLASS_WEAPON_BOW
@ ITEM_SUBCLASS_WEAPON_SWORD
@ ITEM_SUBCLASS_WEAPON_AXE
@ ITEM_SUBCLASS_WEAPON_FIST_WEAPON
@ ITEM_SUBCLASS_WEAPON_EXOTIC
@ ITEM_SUBCLASS_WEAPON_THROWN
@ ITEM_SUBCLASS_WEAPON_SWORD2
@ ITEM_SUBCLASS_WEAPON_POLEARM
#define MAX_ITEM_PROTO_DAMAGES
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
#define TC_LOG_FATAL(filterType__,...)
Definition Log.h:168
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
ZLiquidStatus
Definition MapDefines.h:74
@ LIQUID_MAP_UNDER_WATER
Definition MapDefines.h:79
@ LIQUID_MAP_IN_WATER
Definition MapDefines.h:78
bool IsInvalidMovementSlot(uint8 const slot)
@ MOTION_PRIORITY_HIGHEST
@ MOTION_PRIORITY_NORMAL
MovementSlot
MovementGeneratorType
@ DISTRACT_MOTION_TYPE
@ IDLE_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ CONFUSED_MOTION_TYPE
@ POINT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
#define NOMINAL_MELEE_RANGE
@ NOTIFY_VISIBILITY_CHANGED
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:40
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
@ TYPEMASK_UNIT
Definition ObjectGuid.h:52
#define sObjectMgr
Definition ObjectMgr.h:1721
float const DEFAULT_COLLISION_HEIGHT
Definition Object.h:65
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PETSPELL_REMOVED
Definition PetDefines.h:60
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:45
PetActionFeedback
Definition PetDefines.h:71
#define PET_FOLLOW_DIST
Definition PetDefines.h:85
PetAction
Definition PetDefines.h:80
@ HUNTER_PET
Definition PetDefines.h:32
EquipmentSlots
Definition Player.h:550
@ EQUIPMENT_SLOT_END
Definition Player.h:571
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:568
@ TELE_TO_SPELL
Definition Player.h:683
@ TELE_TO_NOT_LEAVE_COMBAT
Definition Player.h:681
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition Player.h:680
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition Player.h:178
@ CHEAT_GOD
Definition Player.h:837
#define SPELL_DK_RAISE_ALLY
Definition Player.h:893
@ PLAYERSPELL_REMOVED
Definition Player.h:151
#define INVENTORY_SLOT_BAG_0
Definition Player.h:547
int32 irand(int32 min, int32 max)
Definition Random.cpp:35
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
double rand_norm()
Definition Random.cpp:75
bool roll_chance_f(float chance)
Definition Random.h:53
bool roll_chance_i(int chance)
Definition Random.h:59
#define sScriptMgr
Definition ScriptMgr.h:1168
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ EFFECT_0
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_NATURE
@ SPELL_SCHOOL_FROST
@ SPELL_SCHOOL_ARCANE
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
@ SPELL_ATTR7_CANT_MISS
@ SPELL_ATTR7_DISPEL_CHARGES
@ SPELL_ATTR7_CANT_PARRY
@ SPELL_ATTR7_CANT_DODGE
@ SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ SPELL_EFFECT_APPLY_AURA
Language
@ LANG_UNIVERSAL
Gender
@ GENDER_MALE
@ SPELL_ATTR5_REMOVE_ON_ARENA_ENTER
@ NPC_CLICK_CAST_TARGET_CLICKER
@ NPC_CLICK_CAST_ORIG_CASTER_OWNER
@ NPC_CLICK_CAST_CASTER_CLICKER
@ EMOTE_ONESHOT_NONE
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ SPELL_SCHOOL_MASK_NONE
@ SPELL_SCHOOL_MASK_HOLY
@ EVENT_JUMP
@ EVENT_VEHICLE_EXIT
@ SPELL_ATTR2_CAN_TARGET_DEAD
@ SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS
@ SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE
@ CREATURE_TYPE_DEMON
@ SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
@ SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE
SpellSchools GetFirstSchoolInMask(SpellSchoolMask mask)
uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD
@ UNIT_DYNFLAG_SPECIALINFO
@ UNIT_DYNFLAG_TAPPED_BY_PLAYER
@ UNIT_DYNFLAG_TAPPED
@ UNIT_DYNFLAG_LOOTABLE
@ UNIT_DYNFLAG_TRACK_UNIT
@ SPELL_ATTR3_TREAT_AS_PERIODIC
@ SPELL_ATTR3_DEATH_PERSISTENT
@ SPELL_ATTR3_NO_DONE_BONUS
@ SPELL_ATTR3_DISABLE_PROC
@ SPELL_ATTR3_IGNORE_HIT_RESULT
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ AI_REACTION_HOSTILE
@ SUMMON_TYPE_MINIPET
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ CLASS_HUNTER
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_ROGUE
#define PER_CASTER_AURA_STATE_MASK
@ MECHANIC_SLOW_ATTACK
@ MECHANIC_KNOCKOUT
@ MECHANIC_STUN
@ MECHANIC_ROOT
@ MECHANIC_BLEED
@ MECHANIC_DAZE
@ MECHANIC_SNARE
@ IMMUNITY_STATE
@ IMMUNITY_EFFECT
@ IMMUNITY_ID
@ IMMUNITY_DAMAGE
@ IMMUNITY_MECHANIC
@ IMMUNITY_SCHOOL
@ IMMUNITY_DISPEL
SpellFamilyNames
@ SPELLFAMILY_PRIEST
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_PALADIN
@ SPELLFAMILY_HUNTER
@ SPELLFAMILY_POTION
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_SHAMAN
@ SPELLFAMILY_DRUID
@ SPELLFAMILY_DEATHKNIGHT
@ ALLIANCE
@ HORDE
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_HEALTH
@ POWER_RUNIC_POWER
@ POWER_HAPPINESS
@ POWER_ENERGY
@ POWER_MANA
@ POWER_RUNE
@ POWER_FOCUS
@ SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK
@ SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY
@ SPELL_ATTR0_CASTABLE_WHILE_MOUNTED
ChatMsg
@ CHAT_MSG_MONSTER_WHISPER
@ CHAT_MSG_RAID_BOSS_WHISPER
@ CHAT_MSG_RAID_BOSS_EMOTE
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_MONSTER_SAY
@ CHAT_MSG_MONSTER_YELL
DiminishingLevels
@ DIMINISHING_LEVEL_3
@ DIMINISHING_LEVEL_1
@ DIMINISHING_LEVEL_4
@ DIMINISHING_LEVEL_IMMUNE
@ DIMINISHING_LEVEL_TAUNT_IMMUNE
@ DIMINISHING_LEVEL_2
@ DUEL_FLED
@ DUEL_WON
@ DUEL_INTERRUPTED
DiminishingGroup
@ DIMINISHING_NONE
@ DIMINISHING_TAUNT
@ MAX_SUMMON_SLOT
@ GHOST_VISIBILITY_ALIVE
@ SPELL_HIT_TYPE_CRIT
@ SPELL_HIT_TYPE_HIT_DEBUG
@ SPELL_HIT_TYPE_ATTACK_TABLE_DEBUG
@ SPELL_HIT_TYPE_CRIT_DEBUG
@ SPELL_HIT_TYPE_SPLIT
@ RACE_NIGHTELF
@ RACE_TAUREN
SpellMissInfo
@ SPELL_MISS_PARRY
@ SPELL_MISS_IMMUNE
@ SPELL_MISS_ABSORB
@ SPELL_MISS_DODGE
@ SPELL_MISS_IMMUNE2
@ SPELL_MISS_NONE
@ SPELL_MISS_RESIST
@ SPELL_MISS_MISS
@ SPELL_MISS_EVADE
@ SPELL_MISS_REFLECT
@ SPELL_MISS_BLOCK
@ SPELL_MISS_DEFLECT
AuraStateType
@ AURA_STATE_DEFENSE
@ AURA_STATE_FROZEN
@ AURA_STATE_BLEEDING
@ AURA_STATE_FAERIE_FIRE
@ AURA_STATE_ENRAGE
@ AURA_STATE_HEALTHLESS_35_PERCENT
@ AURA_STATE_HEALTH_ABOVE_75_PERCENT
@ AURA_STATE_HEALTHLESS_20_PERCENT
@ AURA_STATE_CONFLAGRATE
@ AURA_STATE_HUNTER_PARRY
@ DRTYPE_PLAYER
@ DRTYPE_ALL
Stats
@ STAT_SPIRIT
@ STAT_INTELLECT
@ MAX_STATS
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
@ DISPEL_DISEASE
#define MAX_GAMEOBJECT_SLOT
SpellCastResult
@ SPELL_CAST_OK
@ SPELL_ATTR4_DONT_REMOVE_IN_ARENA
@ SPELL_ATTR4_IGNORE_RESISTANCES
@ SPELL_ATTR4_FIXED_DAMAGE
@ SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS
@ CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT
@ SKILL_DEFENSE
@ SKILL_UNARMED
@ SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS
@ SPELL_ATTR6_LIMIT_PCT_HEALING_MODS
#define MAX_AURAS
AuraRemoveMode
@ AURA_REMOVE_BY_CANCEL
@ AURA_REMOVE_NONE
@ AURA_REMOVE_BY_DEFAULT
@ AURA_REMOVE_BY_DEATH
@ AURA_REMOVE_BY_EXPIRE
@ AURA_REMOVE_BY_ENEMY_SPELL
@ AURA_EFFECT_HANDLE_STAT
@ AURA_EFFECT_HANDLE_SEND_FOR_CLIENT
@ SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
@ SPELL_AURA_MANA_SHIELD
@ SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
@ SPELL_AURA_CLONE_CASTER
@ SPELL_AURA_RETAIN_COMBO_POINTS
@ SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
@ SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL
@ SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
@ SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
@ SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@ SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS
@ SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
@ SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
@ SPELL_AURA_MOD_PARRY_PERCENT
@ SPELL_AURA_ABILITY_IGNORE_AURASTATE
@ SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE
@ SPELL_AURA_MOD_IGNORE_TARGET_RESIST
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
@ SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT
@ SPELL_AURA_DAMAGE_SHIELD
@ SPELL_AURA_OBS_MOD_HEALTH
@ SPELL_AURA_PERIODIC_HEALTH_FUNNEL
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_MOD_INCREASE_SPEED
@ SPELL_AURA_MOD_RESISTANCE
@ SPELL_AURA_MOD_EXPERTISE
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
@ SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER
@ SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
@ SPELL_AURA_MOD_HEALING_DONE_PERCENT
@ SPELL_AURA_LINKED
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
@ SPELL_AURA_SHARE_DAMAGE_PCT
@ SPELL_AURA_OBS_MOD_POWER
@ SPELL_AURA_ADD_CASTER_HIT_TRIGGER
@ SPELL_AURA_SPLIT_DAMAGE_FLAT
@ SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_IGNORE_HIT_DIRECTION
@ SPELL_AURA_IGNORE_COMBAT_RESULT
@ SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_EMPATHY
@ SPELL_AURA_MOD_SPEED_NOT_STACK
@ SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
@ SPELL_AURA_MOD_STALKED
@ SPELL_AURA_SCHOOL_HEAL_ABSORB
@ SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
@ SPELL_AURA_MOD_HIT_CHANCE
@ SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_MOD_ENEMY_DODGE
@ SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
@ SPELL_AURA_PERIODIC_DAMAGE_PERCENT
@ SPELL_AURA_DUMMY
@ SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
@ SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL
@ SPELL_AURA_MOD_DODGE_PERCENT
@ SPELL_AURA_MOD_INCREASE_SWIM_SPEED
@ SPELL_AURA_FLY
@ SPELL_AURA_SPLIT_DAMAGE_PCT
@ SPELL_AURA_DEFLECT_SPELLS
@ SPELL_AURA_MOD_STAT
@ SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
@ SPELL_AURA_MOD_HEALING_DONE
@ SPELL_AURA_MOD_HEALING_RECEIVED
@ SPELL_AURA_MOD_HEALING_PCT
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
@ SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
@ SPELL_AURA_MOD_ARMOR_PENETRATION_PCT
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
@ SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_DAMAGE_TAKEN
@ SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE
@ SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS
@ SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
@ SPELL_AURA_MOD_CRIT_PCT
@ SPELL_AURA_MOD_MINIMUM_SPEED
@ SPELL_AURA_MOD_BLOCK_CRIT_CHANCE
@ SPELL_AURA_MOD_HOT_PCT
@ SPELL_AURA_MOD_SCALE_2
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_MOD_TARGET_RESISTANCE
@ SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
@ SPELL_AURA_MOD_SPEED_ALWAYS
@ SPELL_AURA_MOD_DECREASE_SPEED
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_SCHOOL_ABSORB
@ SPELL_AURA_MOD_RESISTANCE_PCT
@ SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC
@ SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
@ SPELL_AURA_PERIODIC_ENERGIZE
@ SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
@ SPELL_AURA_MOD_SCALE
@ SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL
@ SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_MOD_DAMAGE_FROM_CASTER
@ SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT
@ SPELL_AURA_MOD_PERCENT_STAT
@ SPELL_AURA_MOD_HEALING
@ SPELL_AURA_MOD_DAMAGE_DONE
@ SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_MECHANIC_RESISTANCE
@ SPELL_AURA_MOD_UNATTACKABLE
@ SPELL_AURA_NONE
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
@ SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
@ SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
@ SPELL_AURA_MOD_BLOCK_PERCENT
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
ShapeshiftForm
@ FORM_DIREBEAR
@ FORM_TRAVEL
@ FORM_FLIGHT_EPIC
@ FORM_CAT
@ FORM_FLIGHT
@ FORM_GHOSTWOLF
@ FORM_GHOUL
@ FORM_BEAR
@ UNIT_AURA_TYPE
@ SPELL_INTERRUPT_FLAG_ABORT_ON_DMG
@ SPELL_INTERRUPT_FLAG_MOVEMENT
@ SPELLMOD_DAMAGE
@ SPELLMOD_CRIT_DAMAGE_BONUS
@ SPELLMOD_DOT
@ SPELLMOD_CRITICAL_CHANCE
@ SPELLMOD_BONUS_MULTIPLIER
@ SPELLMOD_PROC_PER_MINUTE
@ SPELLMOD_IGNORE_ARMOR
@ SPELLMOD_RESIST_MISS_CHANCE
TriggerCastFlags
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Disallows proc events from triggered spell (default)
@ TRIGGERED_NONE
SpellValueMod
@ SPELLVALUE_BASE_POINT0
@ AURA_INTERRUPT_FLAG_TAKE_DAMAGE
@ AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
@ AURA_INTERRUPT_FLAG_MOVE
@ AURA_INTERRUPT_FLAG_TURNING
@ AURA_INTERRUPT_FLAG_NOT_ABOVEWATER
@ AURA_INTERRUPT_FLAG_NOT_SEATED
@ AURA_INTERRUPT_FLAG_NOT_UNDERWATER
@ AURA_INTERRUPT_FLAG_MELEE_ATTACK
@ AURA_INTERRUPT_FLAG_LEAVE_COMBAT
@ AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT
@ AURA_INTERRUPT_FLAG_MOUNT
@ AURA_INTERRUPT_FLAG_NOT_MOUNTED
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:156
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition SpellInfo.h:141
@ SPELL_ATTR0_CU_CAN_CRIT
Definition SpellInfo.h:148
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition SpellInfo.h:158
@ SPELL_ATTR0_CU_AURA_CC
Definition SpellInfo.h:146
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition SpellInfo.h:161
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition SpellInfo.h:162
@ SPELL_SPECIFIC_MAGE_POLYMORPH
Definition SpellInfo.h:124
@ PROC_HIT_BLOCK
Definition SpellMgr.h:226
@ PROC_HIT_FULL_RESIST
Definition SpellMgr.h:223
@ PROC_HIT_FULL_BLOCK
Definition SpellMgr.h:233
@ PROC_HIT_MISS
Definition SpellMgr.h:222
@ PROC_HIT_NONE
Definition SpellMgr.h:219
@ PROC_HIT_DEFLECT
Definition SpellMgr.h:229
@ PROC_HIT_EVADE
Definition SpellMgr.h:227
@ PROC_HIT_DODGE
Definition SpellMgr.h:224
@ PROC_HIT_IMMUNE
Definition SpellMgr.h:228
@ PROC_HIT_ABSORB
Definition SpellMgr.h:230
@ PROC_HIT_PARRY
Definition SpellMgr.h:225
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:221
@ PROC_HIT_NORMAL
Definition SpellMgr.h:220
@ PROC_HIT_REFLECT
Definition SpellMgr.h:231
#define MELEE_BASED_TRIGGER_MASK
Definition SpellMgr.h:190
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:318
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:329
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition SpellMgr.h:330
#define sSpellMgr
Definition SpellMgr.h:738
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:201
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:205
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:202
@ PROC_SPELL_PHASE_NONE
Definition SpellMgr.h:210
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:212
@ PROC_FLAG_DONE_MELEE_AUTO_ATTACK
Definition SpellMgr.h:118
@ PROC_FLAG_KILLED
Definition SpellMgr.h:115
@ PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
Definition SpellMgr.h:140
@ PROC_FLAG_DEATH
Definition SpellMgr.h:151
@ PROC_FLAG_KILL
Definition SpellMgr.h:116
@ PROC_FLAG_DONE_MAINHAND_ATTACK
Definition SpellMgr.h:148
@ PROC_FLAG_TAKEN_DAMAGE
Definition SpellMgr.h:145
@ PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK
Definition SpellMgr.h:119
@ PROC_FLAG_DONE_OFFHAND_ATTACK
Definition SpellMgr.h:149
@ PROC_FLAG_NONE
Definition SpellMgr.h:113
@ SPELL_STATE_DELAYED
Definition Spell.h:136
@ SPELL_STATE_FINISHED
Definition Spell.h:134
@ SPELL_STATE_PREPARING
Definition Spell.h:132
@ SPELL_STATE_CASTING
Definition Spell.h:133
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition Timer.h:40
@ TOTEM_PASSIVE
Definition Totem.h:25
@ UNIT_BYTES_2_OFFSET_SHAPESHIFT_FORM
Definition UnitDefines.h:80
@ UNIT_BYTES_0_OFFSET_POWER_TYPE
Definition UnitDefines.h:64
@ UNIT_FLAG2_UNUSED_6
@ UNIT_FLAG2_DISARM_OFFHAND
@ UNIT_FLAG2_DISARM_RANGED
HitInfo
@ HITINFO_PARTIAL_ABSORB
@ HITINFO_FULL_RESIST
@ HITINFO_NORMALSWING
@ HITINFO_BLOCK
@ HITINFO_CRUSHING
@ HITINFO_SWINGNOHITSOUND
@ HITINFO_MISS
@ HITINFO_RAGE_GAIN
@ HITINFO_FULL_ABSORB
@ HITINFO_OFFHAND
@ HITINFO_UNK1
@ HITINFO_GLANCING
@ HITINFO_CRITICALHIT
@ HITINFO_PARTIAL_RESIST
@ HITINFO_AFFECTS_VICTIM
@ REACT_PASSIVE
UnitStandStateType
Definition UnitDefines.h:33
@ UNIT_STAND_STATE_SLEEP
Definition UnitDefines.h:37
@ UNIT_STAND_STATE_SIT_HIGH_CHAIR
Definition UnitDefines.h:40
@ UNIT_STAND_STATE_SIT_MEDIUM_CHAIR
Definition UnitDefines.h:39
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition UnitDefines.h:38
@ UNIT_STAND_STATE_KNEEL
Definition UnitDefines.h:42
@ UNIT_STAND_STATE_SIT_CHAIR
Definition UnitDefines.h:36
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ UNIT_STAND_STATE_SIT
Definition UnitDefines.h:35
#define BASE_ATTACK_TIME
Definition UnitDefines.h:27
MovementFlags
@ MOVEMENTFLAG_SPLINE_ENABLED
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_ONTRANSPORT
@ MOVEMENTFLAG_WATERWALKING
@ MOVEMENTFLAG_MASK_MOVING
@ MOVEMENTFLAG_DISABLE_GRAVITY
@ MOVEMENTFLAG_FLYING
@ MOVEMENTFLAG_FALLING_SLOW
@ MOVEMENTFLAG_CAN_FLY
@ MOVEMENTFLAG_ROOT
@ MOVEMENTFLAG_MASK_TURNING
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_MASK_MOVING_FLY
@ MOVEMENTFLAG_FALLING_FAR
@ MOVEMENTFLAG_SWIMMING
@ MOVEMENTFLAG_HOVER
@ MOVEMENTFLAG_SPLINE_ELEVATION
@ MOVEMENTFLAG_WALKING
#define MAX_MOVE_TYPE
@ MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING
@ MOVEMENTFLAG2_INTERPOLATED_MOVEMENT
@ UNIT_BYTES_1_OFFSET_ANIM_TIER
Definition UnitDefines.h:72
@ UNIT_BYTES_1_OFFSET_STAND_STATE
Definition UnitDefines.h:69
ActiveStates
@ ACT_REACTION
@ ACT_DECIDE
@ ACT_COMMAND
@ ACT_ENABLED
@ ACT_PASSIVE
@ ACT_DISABLED
@ UNIT_NPC_FLAG_TABARDDESIGNER
@ UNIT_NPC_FLAG_BANKER
@ UNIT_NPC_FLAG_AUCTIONEER
@ UNIT_NPC_FLAG_VENDOR
@ UNIT_NPC_FLAG_BATTLEMASTER
@ UNIT_NPC_FLAG_INNKEEPER
@ UNIT_NPC_FLAG_SPELLCLICK
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
@ UNIT_NPC_FLAG_FLIGHTMASTER
@ UNIT_NPC_FLAG_TRAINER
@ UNIT_NPC_FLAG_PETITIONER
@ UNIT_NPC_FLAG_SPIRITGUIDE
@ UNIT_NPC_FLAG_SPIRITHEALER
#define BASE_MAXDAMAGE
Definition UnitDefines.h:26
#define MAX_EQUIPMENT_ITEMS
Definition UnitDefines.h:29
@ UNIT_BYTE2_FLAG_PVP
@ UNIT_BYTE2_FLAG_NONE
@ UNIT_BYTE2_FLAG_SANCTUARY
AnimTier
Definition UnitDefines.h:85
@ COMMAND_ATTACK
@ COMMAND_FOLLOW
#define BASE_MINDAMAGE
Definition UnitDefines.h:25
UnitMoveType
@ MOVE_FLIGHT
@ MOVE_SWIM
@ MOVE_TURN_RATE
@ MOVE_FLIGHT_BACK
@ MOVE_SWIM_BACK
@ MOVE_RUN
@ MOVE_PITCH_RATE
@ MOVE_RUN_BACK
@ MOVE_WALK
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_CANNOT_SWIM
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_POSSESSED
@ UNIT_FLAG_DISARMED
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_CAN_SWIM
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
@ UNIT_FLAG_RENAME
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_FLAG_IMMUNE_TO_PC
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
@ UNIT_FLAG_MOUNT
@ UNIT_FLAG_PET_IN_COMBAT
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:87
uint32 createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:10001
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition Unit.cpp:10622
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:100
UnitModifierFlatType
Definition Unit.h:137
@ BASE_VALUE
Definition Unit.h:138
@ MODIFIER_TYPE_FLAT_END
Definition Unit.h:140
@ TOTAL_VALUE
Definition Unit.h:139
#define MAX_SPELL_CHARM
Definition Unit.h:37
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition Unit.h:134
@ UNIT_MASK_NONE
Definition Unit.h:363
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:372
@ UNIT_MASK_ACCESSORY
Definition Unit.h:373
@ UNIT_MASK_VEHICLE
Definition Unit.h:369
@ UNIT_MASK_GUARDIAN
Definition Unit.h:366
@ UNIT_MASK_MINION
Definition Unit.h:365
#define MAX_UNIT_ACTION_BAR_INDEX
Definition Unit.h:670
MovementChangeType
Definition Unit.h:275
VictimState
Definition Unit.h:46
@ VICTIMSTATE_INTACT
Definition Unit.h:47
@ VICTIMSTATE_HIT
Definition Unit.h:48
@ VICTIMSTATE_DODGE
Definition Unit.h:49
@ VICTIMSTATE_IS_IMMUNE
Definition Unit.h:54
@ VICTIMSTATE_PARRY
Definition Unit.h:50
@ VICTIMSTATE_BLOCKS
Definition Unit.h:52
@ VICTIMSTATE_EVADES
Definition Unit.h:53
WeaponDamageRange
Definition Unit.h:151
@ MINDAMAGE
Definition Unit.h:152
@ MAXDAMAGE
Definition Unit.h:153
UnitMods
Definition Unit.h:157
@ UNIT_MOD_DAMAGE_OFFHAND
Definition Unit.h:181
@ UNIT_MOD_RUNE
Definition Unit.h:169
@ UNIT_MOD_STAT_INTELLECT
Definition Unit.h:161
@ UNIT_MOD_STAT_SPIRIT
Definition Unit.h:162
@ UNIT_MOD_ARMOR
Definition Unit.h:171
@ UNIT_MOD_RESISTANCE_SHADOW
Definition Unit.h:176
@ UNIT_MOD_RESISTANCE_FROST
Definition Unit.h:175
@ UNIT_MOD_END
Definition Unit.h:183
@ UNIT_MOD_ATTACK_POWER
Definition Unit.h:178
@ UNIT_MOD_RESISTANCE_HOLY
Definition Unit.h:172
@ UNIT_MOD_RESISTANCE_ARCANE
Definition Unit.h:177
@ UNIT_MOD_ENERGY
Definition Unit.h:167
@ UNIT_MOD_HEALTH
Definition Unit.h:163
@ UNIT_MOD_DAMAGE_RANGED
Definition Unit.h:182
@ UNIT_MOD_RESISTANCE_FIRE
Definition Unit.h:173
@ UNIT_MOD_STAT_STRENGTH
Definition Unit.h:158
@ UNIT_MOD_RESISTANCE_NATURE
Definition Unit.h:174
@ UNIT_MOD_STAT_AGILITY
Definition Unit.h:159
@ UNIT_MOD_FOCUS
Definition Unit.h:166
@ UNIT_MOD_DAMAGE_MAINHAND
Definition Unit.h:180
@ UNIT_MOD_HAPPINESS
Definition Unit.h:168
@ UNIT_MOD_MANA
Definition Unit.h:164
@ UNIT_MOD_STAT_START
Definition Unit.h:185
@ UNIT_MOD_RAGE
Definition Unit.h:165
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:160
@ UNIT_MOD_RUNIC_POWER
Definition Unit.h:170
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition Unit.h:179
TC_GAME_API float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:100
@ ACTION_BAR_INDEX_PET_SPELL_START
Definition Unit.h:665
@ ACTION_BAR_INDEX_PET_SPELL_END
Definition Unit.h:666
@ ACTION_BAR_INDEX_END
Definition Unit.h:667
@ ACTION_BAR_INDEX_START
Definition Unit.h:664
DeathState
Definition Unit.h:210
@ CORPSE
Definition Unit.h:213
@ DEAD
Definition Unit.h:214
@ ALIVE
Definition Unit.h:211
@ JUST_RESPAWNED
Definition Unit.h:215
@ JUST_DIED
Definition Unit.h:212
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition Unit.h:612
CurrentSpellTypes
Definition Unit.h:605
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:608
@ CURRENT_GENERIC_SPELL
Definition Unit.h:607
@ CURRENT_MELEE_SPELL
Definition Unit.h:606
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:609
UnitState
Definition Unit.h:219
@ UNIT_STATE_DISTRACTED
Definition Unit.h:232
@ UNIT_STATE_DIED
Definition Unit.h:220
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:234
@ UNIT_STATE_POSSESSED
Definition Unit.h:236
@ UNIT_STATE_UNATTACKABLE
Definition Unit.h:258
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition Unit.h:262
@ UNIT_STATE_CONFUSED
Definition Unit.h:231
@ UNIT_STATE_ROOT
Definition Unit.h:230
@ UNIT_STATE_CONTROLLED
Definition Unit.h:260
@ UNIT_STATE_FLEEING
Definition Unit.h:227
@ UNIT_STATE_CANNOT_TURN
Definition Unit.h:264
@ UNIT_STATE_MOVING
Definition Unit.h:259
@ UNIT_STATE_MOVE
Definition Unit.h:240
@ UNIT_STATE_MELEE_ATTACKING
Definition Unit.h:221
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:228
@ UNIT_STATE_CASTING
Definition Unit.h:235
@ UNIT_STATE_STUNNED
Definition Unit.h:223
@ UNIT_STATE_CHARMED
Definition Unit.h:222
MeleeHitOutcome
Definition Unit.h:393
@ MELEE_HIT_CRUSHING
Definition Unit.h:395
@ MELEE_HIT_BLOCK
Definition Unit.h:394
@ MELEE_HIT_CRIT
Definition Unit.h:395
@ MELEE_HIT_NORMAL
Definition Unit.h:395
@ MELEE_HIT_EVADE
Definition Unit.h:394
@ MELEE_HIT_DODGE
Definition Unit.h:394
@ MELEE_HIT_MISS
Definition Unit.h:394
@ MELEE_HIT_PARRY
Definition Unit.h:394
@ MELEE_HIT_GLANCING
Definition Unit.h:395
#define MAX_AGGRO_RESET_TIME
Definition Unit.h:42
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:132
#define CURRENT_MAX_SPELL
Definition Unit.h:613
CombatRating
Definition Unit.h:321
@ CR_WEAPON_SKILL_RANGED
Definition Unit.h:344
@ CR_CRIT_TAKEN_RANGED
Definition Unit.h:337
@ CR_CRIT_TAKEN_SPELL
Definition Unit.h:338
@ CR_ARMOR_PENETRATION
Definition Unit.h:346
@ CR_WEAPON_SKILL
Definition Unit.h:322
@ CR_WEAPON_SKILL_OFFHAND
Definition Unit.h:343
@ CR_DEFENSE_SKILL
Definition Unit.h:323
@ CR_WEAPON_SKILL_MAINHAND
Definition Unit.h:342
@ CR_CRIT_TAKEN_MELEE
Definition Unit.h:336
DamageEffectType
Definition Unit.h:352
@ DIRECT_DAMAGE
Definition Unit.h:353
@ NODAMAGE
Definition Unit.h:357
@ DOT
Definition Unit.h:355
@ SPELL_DIRECT_DAMAGE
Definition Unit.h:354
CharmType
Definition Unit.h:653
@ CHARM_TYPE_CHARM
Definition Unit.h:654
@ CHARM_TYPE_POSSESS
Definition Unit.h:655
@ CHARM_TYPE_CONVERT
Definition Unit.h:657
@ CHARM_TYPE_VEHICLE
Definition Unit.h:656
ReactiveType
Definition Unit.h:744
@ MAX_REACTIVE
Definition Unit.h:749
@ REACTIVE_OVERPOWER
Definition Unit.h:747
@ REACTIVE_DEFENSE
Definition Unit.h:745
@ REACTIVE_HUNTER_PARRY
Definition Unit.h:746
@ REACTIVE_WOLVERINE_BITE
Definition Unit.h:748
TC_GAME_API float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:87
UnitModifierPctType
Definition Unit.h:144
@ MODIFIER_TYPE_PCT_END
Definition Unit.h:147
@ TOTAL_PCT
Definition Unit.h:146
@ BASE_PCT
Definition Unit.h:145
@ UPDATETYPE_VALUES
Definition UpdateData.h:30
@ UPDATEFLAG_LIVING
Definition UpdateData.h:46
@ UPDATEFLAG_VEHICLE
Definition UpdateData.h:48
@ UPDATEFLAG_STATIONARY_POSITION
Definition UpdateData.h:47
uint32 UnitUpdateFieldFlags[PLAYER_END]
@ UF_FLAG_SPECIAL_INFO
@ UF_FLAG_PUBLIC
@ UF_FLAG_OWNER
@ UF_FLAG_PRIVATE
@ UF_FLAG_PARTY_MEMBER
@ UNIT_FIELD_MINDAMAGE
@ PLAYER_RANGED_CRIT_PERCENTAGE
@ UNIT_NPC_FLAGS
@ PLAYER_CRIT_PERCENTAGE
@ PLAYER_SPELL_CRIT_PERCENTAGE1
@ UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE
@ UNIT_FIELD_POSSTAT0
@ UNIT_FIELD_RANGEDATTACKTIME
@ UNIT_FIELD_HEALTH
@ UNIT_FIELD_ATTACK_POWER_MODS
@ PLAYER_PARRY_PERCENTAGE
@ UNIT_FIELD_SUMMONEDBY
@ PLAYER_OFFHAND_CRIT_PERCENTAGE
@ UNIT_FIELD_MAXDAMAGE
@ UNIT_FIELD_DISPLAYID
@ PLAYER_BLOCK_PERCENTAGE
@ UNIT_FIELD_BYTES_0
@ UNIT_FIELD_LEVEL
@ UNIT_FIELD_FACTIONTEMPLATE
@ UNIT_FIELD_RANGED_ATTACK_POWER
@ UNIT_FIELD_MAXPOWER1
@ UNIT_MOD_CAST_SPEED
@ UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
@ UNIT_FIELD_POSSTAT4
@ UNIT_FIELD_MAXOFFHANDDAMAGE
@ UNIT_FIELD_SUMMON
@ UNIT_FIELD_NEGSTAT4
@ UNIT_FIELD_AURASTATE
@ UNIT_FIELD_MAXRANGEDDAMAGE
@ PLAYER_DODGE_PERCENTAGE
@ UNIT_FIELD_ATTACK_POWER_MULTIPLIER
@ UNIT_FIELD_ATTACK_POWER
@ UNIT_FIELD_POWER1
@ UNIT_FIELD_CHARMEDBY
@ UNIT_FIELD_CHARM
@ UNIT_VIRTUAL_ITEM_SLOT_ID
@ UNIT_FIELD_MINRANGEDDAMAGE
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_RANGED_ATTACK_POWER_MODS
@ UNIT_FIELD_HOVERHEIGHT
@ PLAYER_SELF_RES_SPELL
@ UNIT_FIELD_NEGSTAT0
@ UNIT_FIELD_MAXHEALTH
@ PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
@ UNIT_FIELD_BYTES_1
@ UNIT_FIELD_BYTES_2
@ UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE
@ UNIT_FIELD_MINOFFHANDDAMAGE
@ UNIT_CREATED_BY_SPELL
@ UNIT_FIELD_BASEATTACKTIME
@ UNIT_DYNAMIC_FLAGS
T AddPct(T &base, U pct)
Definition Util.h:77
T RoundToInterval(T &num, T floor, T ceil)
Definition Util.h:89
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
T ApplyPct(T &base, U pct)
Definition Util.h:83
T CalculatePct(T base, U pct)
Definition Util.h:71
@ VEHICLE_SPELL_RIDE_HARDCODED
@ VEHICLE_FLAG_FIXED_POSITION
Unit * GetTarget() const
Definition SpellAuras.h:66
void SetRemoveMode(AuraRemoveMode mode)
Definition SpellAuras.h:79
bool IsPositive() const
Definition SpellAuras.h:73
uint8 GetEffectMask() const
Definition SpellAuras.h:71
void _HandleEffect(uint8 effIndex, bool apply)
Aura * GetBase() const
Definition SpellAuras.h:67
AuraRemoveMode GetRemoveMode() const
Definition SpellAuras.h:80
bool HasEffect(uint8 effect) const
Definition SpellAuras.h:72
void ChangeAmount(int32 newAmount, bool mark=true, bool onStackOrReapply=false)
SpellInfo const * GetSpellInfo() const
AuraType GetAuraType() const
bool CanBeRecalculated() const
SpellEffectInfo const & GetSpellEffectInfo() const
uint32 GetId() const
void HandleEffect(AuraApplication *aurApp, uint8 mode, bool apply)
bool IsAffectingSpell(SpellInfo const *spell) const
void SetAmount(int32 amount)
Unit * GetCaster() const
int32 GetMiscValue() const
Aura * GetBase() const
int32 const m_baseAmount
int32 GetBaseAmount() const
ObjectGuid GetCasterGUID() const
int32 GetAmount() const
bool HasMoreThanOneEffectForType(AuraType auraType) const
virtual void _UnapplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
bool IsArea() const
int32 GetMaxDuration() const
Definition SpellAuras.h:143
void CallScriptEffectAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
virtual std::string GetDebugInfo() const
void CallScriptDispel(DispelInfo *dispelInfo)
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
ApplicationMap const & GetApplicationMap()
Definition SpellAuras.h:207
void SetStackAmount(uint8 num)
Unit * GetUnitOwner() const
Definition SpellAuras.h:122
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
Definition SpellAuras.h:209
ObjectGuid GetCasterGUID() const
Definition SpellAuras.h:119
bool HasEffect(uint8 effIndex) const
Definition SpellAuras.h:199
bool IsRemoved() const
Definition SpellAuras.h:184
float GetCritChance() const
Definition SpellAuras.h:171
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication *aurApp, ProcEventInfo &eventInfo)
WorldObject * GetOwner() const
Definition SpellAuras.h:121
bool IsSingleTargetWith(Aura const *aura) const
bool ModCharges(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool CanStackWith(Aura const *existingAura) const
uint32 GetId() const
Definition SpellAuras.h:116
int32 CalcDispelChance(Unit const *auraTarget, bool offensive) const
bool IsAppliedOnTarget(ObjectGuid guid) const
Definition SpellAuras.h:211
int32 GetDuration() const
Definition SpellAuras.h:148
void UpdateOwner(uint32 diff, WorldObject *owner)
void UnregisterSingleTarget()
bool IsDeathPersistent() const
AuraEffect * GetEffect(uint8 effIndex) const
Definition SpellAuras.h:201
Unit * GetCaster() const
bool CanApplyResilience() const
Definition SpellAuras.h:168
void SetNeedClientUpdateForTargets() const
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
uint8 GetEffectMask() const
Definition SpellAuras.h:202
void SetDuration(int32 duration, bool withMods=false)
void CallScriptEffectAfterAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
void CallScriptEffectManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
AuraObjectType GetType() const
uint8 GetStackAmount() const
Definition SpellAuras.h:164
uint8 GetCharges() const
Definition SpellAuras.h:155
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:115
ObjectGuid GetCastItemGUID() const
Definition SpellAuras.h:118
void HandleAuraSpecificMods(AuraApplication const *aurApp, Unit *caster, bool apply, bool onReapply)
void SetIsSingleTarget(bool val)
Definition SpellAuras.h:189
virtual void _ApplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
bool IsPassive() const
std::unordered_map< ObjectGuid, AuraApplication * > ApplicationMap
Definition SpellAuras.h:104
void CallScriptEffectAfterManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
void CallScriptAfterDispel(DispelInfo *dispelInfo)
void _Remove(AuraRemoveMode removeMode)
bool IsSingleTarget() const
Definition SpellAuras.h:187
bool isArena() const
void append(T value)
Definition ByteBuffer.h:129
static size_t BuildChatPacket(WorldPacket &data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const &senderName="", std::string const &receiverName="", uint32 achievementId=0, bool gmMessage=false, std::string const &channelName="")
Definition Chat.cpp:193
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
void Update(uint32 tdiff)
bool HasPvECombat() const
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
bool HasPvPCombat() const
virtual void OnSpellClick(Unit *, bool)
Definition CreatureAI.h:240
virtual void OnSpellFailed(SpellInfo const *)
Definition CreatureAI.h:152
virtual void KilledUnit(Unit *)
Definition CreatureAI.h:133
float GetSpellDamageMod(int32 Rank) const
Loot loot
Definition Creature.h:209
bool isWorldBoss() const
uint16 GetLootMode() const
Definition Creature.h:222
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition Creature.h:229
void SetLootRecipient(Unit *unit, bool withGroup=true)
bool CanWalk() const
Definition Creature.h:105
bool CanFly() const override
Definition Creature.h:108
void SetLastDamagedTime(time_t val)
Definition Creature.h:350
bool IsEvadingAttacks() const
Definition Creature.h:147
void AllLootRemovedFromCorpse()
bool hasLootRecipient() const
Definition Creature.h:216
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Player * GetLootRecipient() const
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:186
bool IsDamageEnoughForLootingAndReward() const
Definition Creature.h:321
bool isTappedBy(Player const *player) const
bool CanEnterWater() const override
Group * GetLootRecipientGroup() const
void SendAIReaction(AiReaction reactionType)
void CallAssistance()
bool IsInEvadeMode() const
Definition Creature.h:146
CreatureAI * AI() const
Definition Creature.h:154
void LowerPlayerDamageReq(uint32 unDamage)
void ResistDamage(uint32 amount)
Definition Unit.cpp:207
void AbsorbDamage(uint32 amount)
Definition Unit.cpp:199
uint32 m_resist
Definition Unit.h:440
void ModifyDamage(int32 amount)
Definition Unit.cpp:193
Unit * GetVictim() const
Definition Unit.h:459
Unit * GetAttacker() const
Definition Unit.h:458
uint32 m_block
Definition Unit.h:441
SpellInfo const * GetSpellInfo() const
Definition Unit.h:460
uint32 GetHitMask() const
Definition Unit.cpp:232
void BlockDamage(uint32 amount)
Definition Unit.cpp:219
DamageEffectType GetDamageType() const
Definition Unit.h:462
WeaponAttackType GetAttackType() const
Definition Unit.h:463
uint32 GetResist() const
Definition Unit.h:466
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:461
uint32 m_absorb
Definition Unit.h:439
uint32 m_damage
Definition Unit.h:434
uint32 GetBlock() const
Definition Unit.h:467
uint32 m_hitMask
Definition Unit.h:442
DamageInfo(DamageInfo const &dmg1, DamageInfo const &dmg2)
Definition Unit.cpp:119
uint32 GetDamage() const
Definition Unit.h:464
uint32 GetAbsorb() const
Definition Unit.h:465
uint8 GetRemovedCharges() const
Definition Unit.h:406
bool RollDispel() const
Definition Unit.cpp:297
int32 _chance
Definition Unit.h:129
DispelableAura(Aura *aura, int32 dispelChance, uint8 dispelCharges)
Definition Unit.cpp:290
uint32 GetSpellId() const
void KillAllEvents(bool force)
T_VALUES GetValue(FLAG_TYPE flag) const
Definition Object.h:290
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition Object.h:291
WorldSession * GetWorldSession() const
Definition GameClient.h:41
Player * GetBasePlayer() const
Definition GameClient.h:40
std::string GetDebugInfo() const
ObjectGuid GetOwnerGUID() const override
Definition GameObject.h:141
uint32 GetSpellId() const
Definition GameObject.h:148
void Delete()
void SetOwnerGUID(ObjectGuid owner)
Definition GameObject.h:131
void SetRespawnTime(int32 respawn)
Definition Group.h:165
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:2552
uint32 GetMembersCount() const
Definition Group.h:249
ObjectGuid GetLooterGuid() const
Definition Group.cpp:2488
void BroadcastPacket(WorldPacket const *packet, bool ignorePlayersInBGRaid, int group=-1, ObjectGuid ignoredPlayer=ObjectGuid::Empty)
Definition Group.cpp:1808
void UpdateLooterGuid(WorldObject *pLootedObject, bool ifneed=false)
Definition Group.cpp:1946
GroupReference * GetFirstMember()
Definition Group.h:247
void SendLooter(Creature *creature, Player *pLooter)
Definition Group.cpp:1028
bool InitStatsForLevel(uint8 level)
Definition Pet.cpp:861
uint32 _heal
Definition Unit.h:477
Unit * GetHealer() const
Definition Unit.h:490
uint32 _effectiveHeal
Definition Unit.h:478
uint32 GetAbsorb() const
Definition Unit.h:494
uint32 GetEffectiveHeal() const
Definition Unit.h:493
SpellInfo const * GetSpellInfo() const
Definition Unit.h:495
uint32 _absorb
Definition Unit.h:479
uint32 GetHitMask() const
Definition Unit.cpp:252
void SetEffectiveHeal(uint32 amount)
Definition Unit.h:488
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:496
void AbsorbHeal(uint32 amount)
Definition Unit.cpp:242
Unit * GetTarget() const
Definition Unit.h:491
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition Unit.cpp:237
uint32 GetHeal() const
Definition Unit.h:492
uint32 _hitMask
Definition Unit.h:482
void PermBindAllPlayers()
Definition Map.cpp:4129
Definition Item.h:62
ItemTemplate const * GetTemplate() const
Definition Item.cpp:535
bool IsBroken() const
Definition Item.h:105
uint32 GetSkill()
Definition Item.cpp:546
Definition Map.h:281
bool IsDungeon() const
Definition Map.cpp:4236
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition Map.cpp:1108
bool IsRaidOrHeroicDungeon() const
Definition Map.cpp:4251
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f) const
Definition Map.cpp:2458
InstanceMap * ToInstanceMap()
Definition Map.h:520
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition Map.cpp:1081
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4397
void setDeathState(DeathState s) override
Unit * GetOwner() const
bool IsGuardianPet() const
bool HasMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
void LaunchMoveSpline(std::function< void(Movement::MoveSplineInit &init)> &&initializer, uint32 id=0, MovementGeneratorPriority priority=MOTION_PRIORITY_NORMAL, MovementGeneratorType type=EFFECT_MOTION_TYPE)
MovementGeneratorType GetCurrentMovementGeneratorType() const
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false)
void PropagateSpeedChange()
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
void InterruptOnTeleport()
void Update(uint32 diff)
void MoveTargetedHome()
void MoveJumpTo(float angle, float speedXY, float speedZ)
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveFace(float orientation, uint32 id=EVENT_FACE)
void MoveFleeing(Unit *enemy, uint32 time=0)
static void SendSpeedChangeToMover(Unit *unit, UnitMoveType mtype, float newRate)
static MovementChangeType GetChangeTypeByMoveType(UnitMoveType moveType)
static void SendSpeedChangeToObservers(Unit *unit, UnitMoveType mtype, float newRate)
static void SendSpeedChangeToAll(Unit *unit, UnitMoveType mtype, float newRate)
void Stop(bool force=false)
bool isCyclic() const
Definition MoveSpline.h:122
std::string ToString() const
Location ComputePosition() const
bool isFalling() const
Definition MoveSpline.h:123
bool Finalized() const
Definition MoveSpline.h:121
int32 timePassed() const
Definition MoveSpline.h:88
Vector3 FinalDestination() const
Definition MoveSpline.h:124
int32 Duration() const
Definition MoveSpline.h:89
AnimTier GetAnimTier() const
Definition MoveSpline.h:129
bool Initialized() const
Definition MoveSpline.h:98
void updateState(int32 difftime, UpdateHandler &handler)
Definition MoveSpline.h:103
bool HasAnimation() const
Definition MoveSpline.h:128
bool HasStarted() const
Definition MoveSpline.h:133
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
bool IsPlayer() const
Definition ObjectGuid.h:179
PackedGuidWriter WriteAsPacked() const
Definition ObjectGuid.h:152
std::string ToString() const
bool IsGameObject() const
Definition ObjectGuid.h:182
bool IsAnyTypeCreature() const
Definition ObjectGuid.h:178
void Clear()
Definition ObjectGuid.h:150
void SetByteValue(uint16 index, uint8 offset, uint8 value)
Definition Object.cpp:668
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player const *target) const
Definition Object.cpp:214
uint16 m_objectType
Definition Object.h:232
static Creature * ToCreature(Object *o)
Definition Object.h:186
int32 GetInt32Value(uint16 index) const
Definition Object.cpp:243
bool IsPlayer() const
Definition Object.h:179
float GetObjectScale() const
Definition Object.h:84
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static Unit * ToUnit(Object *o)
Definition Object.h:192
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
Player * ToPlayer()
Definition Object.h:182
bool IsInWorld() const
Definition Object.h:73
uint16 GetUInt16Value(uint16 index, uint8 offset) const
Definition Object.cpp:274
virtual void DestroyForPlayer(Player *target, bool onDeath=false) const
Definition Object.cpp:231
uint16 _fieldNotifyFlags
Definition Object.h:248
bool HasDynamicFlag(uint32 flag) const
Definition Object.h:88
bool AddGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:620
void RemoveFieldNotifyFlag(uint16 flag)
Definition Object.h:162
UpdateMask _changesMask
Definition Object.h:244
TypeID GetTypeId() const
Definition Object.h:93
uint32 * m_uint32Values
Definition Object.h:240
uint16 m_valuesCount
Definition Object.h:246
void SetFlag(uint16 index, uint32 newFlag)
Definition Object.cpp:760
void RemoveFlag(uint16 index, uint32 oldFlag)
Definition Object.cpp:775
virtual void SetDynamicFlag(uint32 flag)
Definition Object.h:89
float GetFloatValue(uint16 index) const
Definition Object.cpp:261
void SetGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:699
uint32 GetEntry() const
Definition Object.h:81
bool IsCreature() const
Definition Object.h:185
Creature * ToCreature()
Definition Object.h:188
void SetFloatValue(uint16 index, float value)
Definition Object.cpp:655
bool RemoveGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:637
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:799
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
float * m_floatValues
Definition Object.h:241
virtual void SetObjectScale(float scale)
Definition Object.h:85
void SetFieldNotifyFlag(uint16 flag)
Definition Object.h:161
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:585
uint16 m_updateFlag
Definition Object.h:235
ObjectGuid GetGUID() const
Definition Object.h:79
TypeID m_objectTypeId
Definition Object.h:234
void SetStatInt32Value(uint16 index, int32 value)
Definition Object.cpp:720
static Player * ToPlayer(Object *o)
Definition Object.h:180
void ForceValuesUpdateAtIndex(uint32)
Definition Object.cpp:1777
std::size_t size() const
Definition ObjectGuid.h:278
Definition PetAI.h:30
PetInfo const * GetUnslottedHunterPet() const
Definition PetDefines.h:117
Optional< PetInfo > CurrentPet
Definition PetDefines.h:112
Definition Pet.h:40
void FillPetInfo(PetStable::PetInfo *petInfo) const
Definition Pet.cpp:536
std::string GetDebugInfo() const override
Definition Pet.cpp:2048
bool CreateBaseAtCreatureInfo(CreatureTemplate const *cinfo, Unit *owner)
Definition Pet.cpp:823
bool CreateBaseAtCreature(Creature *creature)
Definition Pet.cpp:790
bool isControlled() const
Definition Pet.h:53
void InitPetCreateSpells()
Definition Pet.cpp:1632
void SetAuraUpdateMaskForRaid(uint8 slot)
Definition Pet.h:144
void StopCastingBindSight() const
Definition Player.cpp:24109
bool HaveAtClient(Object const *u) const
Definition Player.cpp:22068
uint32 GetTeam() const
Definition Player.h:1832
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:23743
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2297
void SendAttackSwingCancelAttack() const
Definition Player.cpp:20067
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2177
void DuelComplete(DuelCompleteType type)
Definition Player.cpp:6937
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5892
void SendAutoRepeatCancel(Unit *target)
Definition Player.cpp:20087
PetStable & GetOrInitPetStable()
Definition Player.cpp:25983
float GetRatingBonusValue(CombatRating cr) const
Definition Player.cpp:5199
void CharmSpellInitialize()
Definition Player.cpp:20724
bool isAllowedToLoot(Creature const *creature) const
Definition Player.cpp:17604
void UpdatePvPState(bool onlyFFA=false)
Definition Player.cpp:21644
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1=0, uint32 miscValue2=0, WorldObject *ref=nullptr)
Definition Player.cpp:24940
bool InBattleground() const
Definition Player.h:1982
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4654
void PetSpellInitialize()
Definition Player.cpp:20596
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items.
Definition Player.h:1685
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:24853
Pet * GetPet() const
Definition Player.cpp:20286
uint32 GetResurrectionSpellId()
Definition Player.cpp:23530
void SendRemoveControlBar() const
Definition Player.cpp:20779
WorldSession * GetSession() const
Definition Player.h:1719
OutdoorPvP * GetOutdoorPvP() const
Definition Player.cpp:23422
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:7660
static uint32 TeamForRace(uint8 race)
Definition Player.cpp:6269
uint16 GetMaxSkillValue(uint32 skill) const
Definition Player.cpp:5907
void RewardPlayerAndGroupAtKill(Unit *victim, bool isBattleGround)
Definition Player.cpp:23631
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:1534
void StopCastingCharm()
Definition Player.cpp:20414
Battleground * GetBattleground() const
Definition Player.cpp:23049
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition Player.cpp:5204
Group * GetGroup()
Definition Player.h:2171
bool IsGameMaster() const
Definition Player.h:998
void PossessSpellInitialize()
Definition Player.cpp:20645
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9607
std::unique_ptr< DuelInfo > duel
Definition Player.h:1602
uint8 GetSubGroup() const
Definition Player.h:2175
void VehicleSpellInitialize()
Definition Player.cpp:20673
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1747
void SetFactionForRace(uint8 race)
Definition Player.cpp:6295
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:20212
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:25212
void UpdateCombatSkills(Unit *victim, WeaponAttackType attType, bool defense)
Definition Player.cpp:5645
bool CanSeeSpellClickOn(Creature const *creature) const
Definition Player.cpp:25236
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:21687
bool IsInSameGroupWith(Player const *p) const
Definition Player.cpp:2290
DamageInfo * _damageInfo
Definition Unit.h:532
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:279
HealInfo * _healInfo
Definition Unit.h:533
ProcEventInfo(Unit *actor, Unit *actionTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:257
Spell const * GetProcSpell() const
Definition Unit.h:522
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:268
Spell * _spell
Definition Unit.h:531
Mechanics Mechanic
Definition SpellInfo.h:222
AuraType ApplyAuraName
Definition SpellInfo.h:211
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
SpellEffects Effect
Definition SpellInfo.h:210
bool IsEffect() const
float BonusCoefficient
Definition SpellInfo.h:219
SpellEffIndex EffectIndex
Definition SpellInfo.h:209
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false)
uint32 MaxLevel
Definition SpellInfo.h:327
uint32 GetMaxTicks() const
Mechanics GetEffectMechanic(SpellEffIndex effIndex) const
SpellInfo const * GetFirstRankSpell() const
bool IsAutocastable() const
uint32 GetCategory() const
bool IsRequiringDeadTarget() const
flag96 SpellFamilyFlags
Definition SpellInfo.h:357
DiminishingLevels GetDiminishingReturnsMaxLevel(bool triggered) const
bool IsGroupBuff() const
bool IsDeathPersistent() const
bool IsCooldownStartedOnEvent() const
bool IsPassive() const
uint32 Mechanic
Definition SpellInfo.h:292
uint32 Id
Definition SpellInfo.h:289
bool IsStackableOnOneSlotWithDifferentCasters() const
uint32 GetDispelMask() const
uint32 CalcCastTime(Spell *spell=nullptr) const
SpellSpecificType GetSpellSpecific() const
uint32 Dispel
Definition SpellInfo.h:291
bool IsMultiSlotAura() const
int32 GetMaxDuration() const
uint32 SchoolMask
Definition SpellInfo.h:361
uint32 CasterAuraState
Definition SpellInfo.h:308
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
DiminishingGroup GetDiminishingReturnsGroupForSpell(bool triggered) const
bool IsItemFitToSpellRequirements(Item const *item) const
uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
WeaponAttackType GetAttackType() const
SpellSchoolMask GetSchoolMask() const
AuraStateType GetAuraState() const
bool IsChanneled() const
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
uint32 Attributes
Definition SpellInfo.h:293
bool IsPassiveStackableWithRanks() const
int32 GetDiminishingReturnsLimitDuration(bool triggered) const
int32 GetDuration() const
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
uint32 GetAllEffectsMechanicMask() const
bool CanPierceImmuneAura(SpellInfo const *auraSpellInfo) const
uint32 SpellIconID
Definition SpellInfo.h:349
bool NeedsExplicitUnitTarget() const
DiminishingReturnsType GetDiminishingReturnsGroupType(bool triggered) const
bool HasEffect(SpellEffects effect) const
bool IsPositive() const
uint32 DmgClass
Definition SpellInfo.h:358
bool IsRangedWeaponSpell() const
bool HasAura(AuraType aura) const
std::array< SpellEffectInfo, MAX_SPELL_EFFECTS > const & GetEffects() const
Definition SpellInfo.h:482
uint32 SpellFamilyName
Definition SpellInfo.h:356
uint32 AuraInterruptFlags
Definition SpellInfo.h:322
bool IsPositiveEffect(uint8 effIndex) const
bool IsSingleTarget() const
Definition Spell.h:152
SpellInfo const * GetSpellInfo() const
Definition Spell.h:452
void cast(bool skipCheck=false)
Definition Spell.cpp:3323
bool IsInterruptable() const
Definition Spell.h:436
void SendChannelUpdate(uint32 time)
Definition Spell.cpp:4676
bool IsProcDisabled() const
Definition Spell.cpp:7535
int32 GetCastTime() const
Definition Spell.h:420
uint32 getState() const
Definition Spell.h:356
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:8334
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:7402
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:3271
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3070
Spell ** m_selfContainer
Definition Spell.h:461
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:435
UsedSpellMods m_appliedMods
Definition Spell.h:418
SpellCastResult CheckCast(bool strict, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:5178
void finish(bool ok=true)
Definition Spell.cpp:3912
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:4177
SpellInfo const *const m_spellInfo
Definition Spell.h:395
virtual void UnSummon(uint32 msTime=0)
SummonPropertiesEntry const *const m_Properties
Unit * GetSummonerUnit() const
void ForwardThreatForAssistingMe(Unit *assistant, float baseAmount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false)
== AFFECT OTHERS' THREAT LISTS ==
bool IsThreatListEmpty(bool includeOffline=false) const
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
uint32 GetSpell(uint8 slot=0) const
Definition Totem.h:47
Utility class to enable range for loop syntax for multimap.equal_range uses.
constexpr end_iterator end() const
constexpr iterator begin() const
virtual void OnCharmed(bool isNew)
Definition UnitAI.cpp:42
Definition Unit.h:769
float GetUnitMissChance() const
Definition Unit.cpp:2661
float GetSpellCritChanceReduction() const
Definition Unit.h:1055
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition Unit.cpp:12569
int32 ModifyHealth(int32 val)
Definition Unit.cpp:8381
static uint32 DealDamage(Unit *attacker, Unit *victim, uint32 damage, CleanDamage const *cleanDamage=nullptr, DamageEffectType damagetype=DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *spellProto=nullptr, bool durabilityLoss=true)
Definition Unit.cpp:716
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition Unit.cpp:9095
uint32 m_reactiveTimer[MAX_REACTIVE]
Definition Unit.h:1895
Unit * GetCharmed() const
Definition Unit.h:1256
void ClearUnitState(uint32 f)
Definition Unit.h:877
void OutDebugInfo() const
Definition Unit.cpp:13113
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition Unit.cpp:619
void SendComboPoints()
Definition Unit.cpp:10495
bool IsStopped() const
Definition Unit.h:1671
bool IsVehicle() const
Definition Unit.h:887
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:5910
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition Unit.h:782
uint32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype) const
Definition Unit.cpp:7558
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8439
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:988
bool IsUnderLastManaUseEffect() const
Definition Unit.cpp:10851
void SetImmuneToAll(bool apply, bool keepCombat)
Definition Unit.cpp:8303
bool IsCharmed() const
Definition Unit.h:1280
void BuildValuesUpdate(uint8 updatetype, ByteBuffer *data, Player const *target) const override
Definition Unit.cpp:13574
void SetImmuneToPC(bool apply, bool keepCombat)
Definition Unit.cpp:8316
bool m_duringRemoveFromWorld
Definition Unit.h:1970
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3561
Vehicle * GetVehicle() const
Definition Unit.h:1737
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag96 familyFlags) const
Definition Unit.cpp:671
void SetVisible(bool x)
Definition Unit.cpp:8513
virtual bool IsMovementPreventedByCasting() const
Definition Unit.cpp:3123
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3765
void AddComboPointHolder(Unit *unit)
Definition Unit.h:1704
void JumpTo(float speedXY, float speedZ, bool forward=true, Optional< Position > dest={})
Definition Unit.cpp:12454
bool HealthAbovePct(int32 pct) const
Definition Unit.h:919
void DeleteCharmInfo()
Definition Unit.cpp:9738
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5111
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition Unit.cpp:8367
bool IsHunterPet() const
Definition Unit.h:885
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1384
uint32 GetSchoolImmunityMask() const
Definition Unit.cpp:7781
Spell * m_currentSpells[CURRENT_MAX_SPELL]
Definition Unit.h:1864
bool IsBlockCritical()
Definition Unit.cpp:2352
void SetAnimTier(AnimTier animTier)
Definition Unit.cpp:10391
bool IsCharmerOrSelfPlayer() const
Definition Unit.h:1294
float m_baseSpellCritChance
Definition Unit.h:1500
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition Unit.h:1568
uint32 GetMechanicImmunityMask() const
Definition Unit.cpp:7801
void AIUpdateTick(uint32 diff)
Definition Unit.cpp:9514
Unit * GetCharmerOrSelf() const
Definition Unit.cpp:6298
virtual void RecalculateObjectScale()
Definition Unit.cpp:10399
float CalculateSpellpowerCoefficientLevelPenalty(SpellInfo const *spellInfo) const
Definition Unit.cpp:2326
virtual MovementGeneratorType GetDefaultMovementType() const
Definition Unit.cpp:10307
AuraList m_removedAuras
Definition Unit.h:1868
uint32 GetUnitMovementFlags() const
Definition Unit.h:1679
LiquidTypeEntry const * _lastLiquid
Definition Unit.h:1902
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4439
AuraApplication * GetVisibleAura(uint8 slot) const
Definition Unit.cpp:640
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7300
void _UpdateAutoRepeatSpell()
Definition Unit.cpp:2902
virtual void SetTarget(ObjectGuid)=0
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition Unit.cpp:12193
float GetRangedCritChanceReduction() const
Definition Unit.h:1054
float GetTotalAuraModValue(UnitMods unitMod) const
Definition Unit.cpp:9242
void RestoreDisabledAI()
Definition Unit.cpp:9568
void Heartbeat() override
Definition Unit.cpp:502
void RemoveAllControlled()
Definition Unit.cpp:6253
Pet * ToPet()
Definition Unit.h:1788
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1122
Movement::MoveSpline * movespline
Definition Unit.h:1804
void RemoveAurasByShapeShift()
Definition Unit.cpp:4109
float GetTotalStatValue(Stats stat) const
Definition Unit.cpp:9229
void SetGender(Gender gender)
Definition Unit.h:899
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition Unit.cpp:2744
bool IsContestedGuard() const
Definition Unit.cpp:11948
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition Unit.h:1966
std::unordered_set< Unit * > m_ComboPointHolders
Definition Unit.h:1963
void UpdateUnitMod(UnitMods unitMod)
Definition Unit.cpp:9106
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition Unit.cpp:9185
float GetSpeed(UnitMoveType mtype) const
Definition Unit.cpp:8668
bool SetFall(bool enable)
Definition Unit.cpp:13339
void _UnregisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5033
bool m_canModifyStats
Definition Unit.h:1881
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4457
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3638
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12180
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, Powers powerType)
Definition Unit.cpp:6429
std::shared_ptr< UnitAI > i_AI
Definition Unit.h:1956
void SetCurrentCastSpell(Spell *pSpell)
Definition Unit.cpp:2945
bool _isCombatDisallowed
Definition Unit.h:1980
void SetFullHealth()
Definition Unit.h:927
void SetMinionGUID(ObjectGuid guid)
Definition Unit.h:1246
Diminishing m_Diminishing
Definition Unit.h:1944
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition Unit.cpp:12941
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition Unit.cpp:3532
void SetConfused(bool apply)
Definition Unit.cpp:11463
void _UpdateSpells(uint32 time)
Definition Unit.cpp:2842
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void RemoveNotOwnSingleTargetAuras(uint32 newPhase=0x0)
Definition Unit.cpp:3975
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition Unit.h:985
void AddToWorld() override
Definition Unit.cpp:9592
void RestoreFaction()
Definition Unit.cpp:11776
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition Unit.cpp:8170
virtual void AtExitCombat()
Definition Unit.cpp:8780
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition Unit.cpp:3421
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4555
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1146
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:13834
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition Unit.cpp:10302
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition Unit.cpp:693
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition Unit.cpp:4328
std::vector< std::pair< uint8, AuraApplication * > > AuraApplicationProcContainer
Definition Unit.h:792
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11256
uint8 GetClass() const
Definition Unit.h:895
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9258
void SetStunned(bool apply)
Definition Unit.cpp:11355
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9278
void PushPendingMovementChange(PlayerMovementPendingChange newChange)
Definition Unit.cpp:12960
uint32 m_state
Definition Unit.h:1941
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition Unit.cpp:12478
bool CanUseAttackType(uint8 attacktype) const
Definition Unit.cpp:2382
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:603
std::list< Aura * > AuraList
Definition Unit.h:788
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except=0)
Definition Unit.cpp:4022
void SendPetAIReaction(ObjectGuid guid) const
Definition Unit.cpp:10288
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition Unit.cpp:4547
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition Unit.cpp:3108
uint32 GetMountDisplayId() const
Definition Unit.h:1014
void UpdateAllDamageDoneMods()
Definition Unit.cpp:9179
Vehicle * m_vehicle
Definition Unit.h:1898
Totem * ToTotem()
Definition Unit.h:1791
Creature * GetVehicleCreatureBase() const
Definition Unit.cpp:11847
void UpdateDisplayPower()
Definition Unit.cpp:5453
uint32 MeleeDamageBonusTaken(Unit *attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:8033
float GetCollisionHeight() const override
Definition Unit.cpp:13924
GameClient * _gameClientMovingMe
Definition Unit.h:1891
void RemoveAllGameObjects()
Definition Unit.cpp:5172
static void DealHeal(HealInfo &healInfo)
Definition Unit.cpp:6164
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK, uint8 damageIndex=0) const =0
bool isPossessedByPlayer() const
Definition Unit.cpp:6280
void SendClearTarget()
Definition Unit.cpp:13155
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:780
void _RegisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5028
SpellHistory * _spellHistory
Definition Unit.h:1976
void UpdateSpeed(UnitMoveType mtype)
Definition Unit.cpp:8523
bool IsMovedByClient() const
Definition Unit.h:1300
bool IsPolymorphed() const
Definition Unit.cpp:10378
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1490
void SetFaction(uint32 faction) override
Definition Unit.h:974
virtual void SetPvP(bool state)
Definition Unit.cpp:11956
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1241
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition Unit.cpp:10591
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3149
float CalculateDefaultCoefficient(SpellInfo const *spellInfo, DamageEffectType damagetype) const
Definition Unit.cpp:10789
float GetCombatRatingReduction(CombatRating cr) const
Definition Unit.cpp:12221
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition Unit.cpp:3817
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4420
uint32 SpellHealingBonusDone(Unit *victim, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, Optional< float > const &donePctTotal, uint32 stack=1) const
Definition Unit.cpp:7334
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition Unit.cpp:2008
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:13839
void CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=BASE_ATTACK, bool crit=false, bool blocked=false, Spell *spell=nullptr)
Definition Unit.cpp:995
void StopMoving(bool force=false)
Definition Unit.cpp:10312
Unit * GetVehicleRoot() const
Definition Unit.cpp:11831
void SetCantProc(bool apply)
Definition Unit.cpp:10778
Unit * GetCharmer() const
Definition Unit.h:1253
void SetSpeed(UnitMoveType mtype, float newValue)
Definition Unit.cpp:8673
void ClearComboPoints()
Definition Unit.cpp:10480
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition Unit.cpp:9075
Unit * getAttackerForHelper() const
Definition Unit.cpp:5512
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2615
void SendMeleeAttackStart(Unit *victim)
Definition Unit.cpp:2334
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition Unit.cpp:10856
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition Unit.h:1899
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex=0) const
Definition Unit.cpp:9330
bool IsInDisallowedMountForm() const
Definition Unit.cpp:8975
uint32 GetDefenseSkillValue(Unit const *target=nullptr) const
Definition Unit.cpp:2557
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition Unit.cpp:9042
void SendSpellDamageImmune(Unit *target, uint32 spellId)
Definition Unit.cpp:5309
virtual bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7691
UnitPVPStateFlags GetPvpFlags() const
Definition Unit.h:981
void SendTeleportPacket(Position const &pos, bool teleportingTransport=false)
Definition Unit.cpp:12849
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition Unit.cpp:9149
void _removeAttacker(Unit *pAttacker)
Definition Unit.cpp:5507
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition Unit.cpp:5319
uint32 GetTransformSpell() const
Definition Unit.h:1588
bool IsGhouled() const
Definition Unit.cpp:8723
void RemoveAllAurasExceptType(AuraType type)
Definition Unit.cpp:4272
void TriggerAurasProcOnEvent(Unit *actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:10189
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1109
uint32 _lastExtraAttackSpell
Definition Unit.h:1965
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition Unit.cpp:1769
CharmInfo * m_charmInfo
Definition Unit.h:1889
PlayerMovementPendingChange PopPendingMovementChange()
Definition Unit.cpp:12953
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
MotionMaster * i_motionMaster
Definition Unit.h:1893
virtual bool CanFly() const =0
void ReplaceAllUnitFlags(UnitFlags flags)
Definition Unit.h:956
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition Unit.cpp:12010
Unit * GetVehicleBase() const
Definition Unit.cpp:11826
bool haveOffhandWeapon() const
Definition Unit.cpp:510
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool SetFeatherFall(bool enable)
Definition Unit.cpp:13463
bool IsPet() const
Definition Unit.h:884
Powers GetPowerType() const
Definition Unit.h:931
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:953
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition Unit.cpp:1585
void _addAttacker(Unit *pAttacker)
Definition Unit.cpp:5502
void RemoveVisibleAura(uint8 slot)
Definition Unit.cpp:654
GameClient * GetGameClientMovingMe() const
Definition Unit.h:1302
bool _instantCast
Definition Unit.h:1971
void Dismount()
Definition Unit.cpp:8234
void SetCharm(Unit *target, bool apply)
Definition Unit.cpp:6087
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1255
void RemoveAurasWithFamily(SpellFamilyNames family, flag96 const &familyFlag, ObjectGuid casterGUID)
Definition Unit.cpp:4051
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:964
bool SetHover(bool enable, bool updateAnimTier=true)
Definition Unit.cpp:13503
bool CanDualWield() const
Definition Unit.h:837
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3063
void UpdateInterruptMask()
Definition Unit.cpp:660
void StartReactiveTimer(ReactiveType reactive)
Definition Unit.h:1719
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:9679
uint32 GetMaxHealth() const
Definition Unit.h:914
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition Unit.cpp:10339
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11964
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4359
bool isAttackingPlayer() const
Definition Unit.cpp:5718
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT]
Definition Unit.h:1488
UnitAIStack i_AIs
Definition Unit.h:1955
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype) const
Definition Unit.cpp:6593
virtual void UpdateResistances(uint32 school)=0
int32 GetMaxNegativeAuraModifier(AuraType auraType) const
Definition Unit.cpp:4807
void UpdateSplineMovement(uint32 t_diff)
Definition Unit.cpp:528
uint32 GetSpellCritDamageReduction(uint32 damage) const
Definition Unit.h:1060
float GetMeleeCritChanceReduction() const
Definition Unit.h:1053
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:959
bool CanFreeMove() const
Definition Unit.cpp:9338
std::string GetDebugInfo() const override
Definition Unit.cpp:13950
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition Unit.h:777
uint32 GetRangedDamageReduction(uint32 damage) const
Definition Unit.h:1064
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition Unit.cpp:5804
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3144
float m_createStats[MAX_STATS]
Definition Unit.h:1847
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition Unit.h:1878
bool HasAuraWithMechanic(uint32 mechanicMask) const
Definition Unit.cpp:4602
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition Unit.cpp:8339
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10327
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1291
bool IsSplineEnabled() const
Definition Unit.cpp:13569
void RemoveAllAurasRequiringDeadTarget()
Definition Unit.cpp:4251
void UpdateReactives(uint32 p_time)
Definition Unit.cpp:10549
bool IsAlive() const
Definition Unit.h:1234
virtual bool CanApplyResilience() const
Definition Unit.cpp:12027
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4639
float m_modRangedHitChance
Definition Unit.h:1498
float GetCombatReach() const override
Definition Unit.h:839
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition Unit.cpp:8791
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition Unit.cpp:1653
DeathState m_deathState
Definition Unit.h:1852
std::deque< PlayerMovementPendingChange > m_pendingMovementChanges
Definition Unit.h:1986
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition Unit.cpp:10627
int32 GetMinPower(Powers) const
Definition Unit.h:935
uint32 m_unitTypeMask
Definition Unit.h:1901
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition Unit.h:781
int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4842
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6420
void AddPlayerToVision(Player *player)
Definition Unit.cpp:6358
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:1098
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6405
void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker)
Definition Unit.cpp:13043
int32 GetMaxPositiveAuraModifier(AuraType auraType) const
Definition Unit.cpp:4802
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5077
virtual ~Unit()
Definition Unit.cpp:400
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12680
float SpellCritChanceTaken(Unit const *caster, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7069
uint32 m_removedAurasCount
Definition Unit.h:1870
uint32 GetRangedCritDamageReduction(uint32 damage) const
Definition Unit.h:1059
void RemoveAllAurasOnDeath()
Definition Unit.cpp:4228
uint32 m_movementCounter
Definition Unit.h:1985
void SetHealth(uint32 val)
Definition Unit.cpp:9361
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5185
void RemoveVehicleKit()
Definition Unit.cpp:11808
bool IsStandState() const
Definition Unit.cpp:10357
TempSummon * ToTempSummon()
Definition Unit.h:1794
void SetMaxPower(Powers power, uint32 val)
Definition Unit.cpp:9462
bool IsGravityDisabled() const
Definition Unit.h:1218
PlayerMovementPendingChange & PeakFirstPendingMovementChange()
Definition Unit.cpp:12948
CharmInfo * GetCharmInfo()
Definition Unit.h:1287
ControlList m_Controlled
Definition Unit.h:1276
bool IsInCombatWith(Unit const *who) const
Definition Unit.h:1145
void DisableSpline()
Definition Unit.cpp:592
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1260
int32 GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition Unit.cpp:2359
int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4872
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
Unit * m_comboTarget
Definition Unit.h:1961
AuraMap::iterator m_auraUpdateIterator
Definition Unit.h:1869
UnitAI * GetAI() const
Definition Unit.h:800
std::list< AuraApplication * > AuraApplicationList
Definition Unit.h:789
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6221
ObjectGuid _lastDamagedTargetGuid
Definition Unit.h:1967
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13286
void SetSpeedRateReal(UnitMoveType mtype, float rate)
Definition Unit.cpp:8707
void RemoveAurasWithAttribute(uint32 flags)
Definition Unit.cpp:3963
void RemoveAllFollowers()
Definition Unit.cpp:8717
bool m_AutoRepeatFirstCast
Definition Unit.h:1845
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask=0) const
Definition Unit.cpp:2274
void _DeleteRemovedAuras()
Definition Unit.cpp:2831
uint32 m_attackTimer[MAX_ATTACK]
Definition Unit.h:1503
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition Unit.cpp:6306
Powers GetPowerTypeByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9297
void SetVirtualItem(uint32 slot, uint32 itemId)
Definition Unit.cpp:13868
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:821
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition Unit.h:785
int32 GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4812
void AddUnitState(uint32 f)
Definition Unit.h:875
void ClearComboPointHolders()
Definition Unit.cpp:10528
float SpellCritChanceDone(SpellInfo const *spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7015
float GetTotalAuraMultiplier(AuraType auraType) const
Definition Unit.cpp:4797
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition Unit.cpp:8184
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:11821
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition Unit.cpp:5299
void RemoveComboPointHolder(Unit *unit)
Definition Unit.h:1705
uint32 SpellDamageBonusDone(Unit *victim, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, Optional< float > const &donePctTotal, uint32 stack=1) const
Definition Unit.cpp:6453
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3154
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1261
Gender GetGender() const
Definition Unit.h:898
Unit * EnsureVictim() const
Definition Unit.h:861
int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4882
uint32 getAttackTimer(WeaponAttackType type) const
Definition Unit.h:834
void RefreshAI()
Definition Unit.cpp:9546
void CheckPendingMovementAcks()
Definition Unit.cpp:12974
bool IsDuringRemoveFromWorld() const
Definition Unit.h:1786
bool m_ControlledByPlayer
Definition Unit.h:1843
void SetFeared(bool apply)
Definition Unit.cpp:11428
void AddInterruptMask(uint32 flags)
Definition Unit.h:1577
Unit * GetCharmerOrOwner() const
Definition Unit.h:1265
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition Unit.cpp:4651
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition Unit.cpp:3929
virtual void UpdateDamagePhysical(WeaponAttackType attType)
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13259
virtual Gender GetNativeGender() const
Definition Unit.h:900
void _ApplyAllAuraStatMods()
Definition Unit.cpp:4353
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType)
Definition Unit.cpp:10075
uint32 GetCreatureType() const
Definition Unit.cpp:8940
void AddGameObject(GameObject *gameObj)
Definition Unit.cpp:5093
void RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition Unit.cpp:4077
void InterruptMovementBasedAuras()
Definition Unit.cpp:582
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7811
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition Unit.cpp:13753
bool IsThreatened() const
Definition Unit.cpp:8362
bool SetSwim(bool enable)
Definition Unit.cpp:13355
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const *target=nullptr) const
Definition Unit.cpp:2786
void SetEmoteState(Emote emote)
Definition Unit.h:967
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, Aura *except=nullptr) const
Definition Unit.cpp:3622
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition Unit.cpp:12890
DynObjectList m_dynObj
Definition Unit.h:1857
int32 GetHealthGain(int32 dVal)
Definition Unit.cpp:8413
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition Unit.cpp:4832
PositionUpdateInfo _positionUpdateInfo
Definition Unit.h:1978
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:983
bool SetCanFly(bool enable, bool packetOnly=false)
Definition Unit.cpp:13374
AuraApplicationList m_interruptableAuras
Definition Unit.h:1874
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4862
uint32 GetDisplayId() const
Definition Unit.h:1582
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:13860
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1726
int8 m_comboPoints
Definition Unit.h:1962
void ModifyAuraState(AuraStateType flag, bool apply)
Definition Unit.cpp:5749
bool IsAIEnabled() const
Definition Unit.h:798
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4519
UnitAI * GetTopAI() const
Definition Unit.h:806
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition Unit.cpp:2122
bool isPossessing() const
Definition Unit.cpp:6290
uint32 GetNativeDisplayId() const
Definition Unit.h:1584
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition Unit.cpp:4314
virtual void UpdateArmor()=0
bool HealthBelowPct(int32 pct) const
Definition Unit.h:917
void UpdateCharmAI()
Definition Unit.cpp:9686
void ClearAllReactives()
Definition Unit.cpp:10534
void ApplyControlStatesIfNeeded()
Definition Unit.cpp:11339
void SetRooted(bool apply)
Definition Unit.cpp:11386
void AddUnitMovementFlag(uint32 f)
Definition Unit.h:1676
ThreatManager m_threatManager
Definition Unit.h:1950
uint32 _oldFactionId
faction before charm
Definition Unit.h:1973
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5535
bool IsHovering() const
Definition Unit.h:1220
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4902
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const override
Definition Unit.cpp:12102
void UpdateAuraForGroup(uint8 slot)
Definition Unit.cpp:10751
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4505
bool PopAI()
Definition Unit.cpp:9535
ObjectGuid GetMinionGUID() const
Definition Unit.h:1245
bool isPossessed() const
Definition Unit.h:1282
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1678
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:5240
bool HasNegativeAuraWithInterruptFlag(uint32 flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4590
Unit * m_charmed
Definition Unit.h:1888
AuraApplication * _CreateAuraApplication(Aura *aura, uint8 effMask)
Definition Unit.cpp:3314
uint32 GetMaxPower(Powers power) const
Definition Unit.h:936
virtual void UpdateMaxPower(Powers power)=0
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true, SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Unit.cpp:3021
void _AddAura(UnitAura *aura, Unit *caster)
Definition Unit.cpp:3275
AttackerSet m_attackers
Definition Unit.h:1849
bool IsSummon() const
Definition Unit.h:882
bool IsInWater() const
Definition Unit.cpp:3162
uint32 GetHealth() const
Definition Unit.h:913
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition Unit.cpp:11866
uint32 GetFaction() const override
Definition Unit.h:973
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition Unit.cpp:13844
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5054
Unit * m_attacking
Definition Unit.h:1850
void SetPower(Powers power, uint32 val, bool withPowerUpdate=true, bool force=false)
Definition Unit.cpp:9421
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:5815
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4463
AttackerSet const & getAttackers() const
Definition Unit.h:857
float m_weaponDamage[MAX_ATTACK][2][2]
Definition Unit.h:1880
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:984
void SetAI(UnitAI *newAI)
Definition Unit.cpp:9529
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4373
void SendPlaySpellVisualKit(uint32 id, uint32 type) const
Definition Unit.cpp:12019
std::multimap< uint32, Aura * > AuraMap
Definition Unit.h:776
virtual uint32 GetShieldBlockValue() const =0
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3800
bool IsVisible() const
Definition Unit.cpp:8508
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4542
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3724
bool isMoving() const
Definition Unit.h:1759
bool SetWalk(bool enable)
Definition Unit.cpp:13268
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2671
void SendPetActionSound(PetAction action) const
Definition Unit.cpp:10268
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8292
void NearTeleportTo(Position const &pos, bool casting=false)
Definition Unit.cpp:12832
void PurgeAndApplyPendingMovementChanges(bool informObservers=true)
Definition Unit.cpp:13005
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition Unit.cpp:1134
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition Unit.cpp:2398
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition Unit.h:832
virtual bool UpdateStats(Stats stat)=0
void RemoveAllDynObjects()
Definition Unit.cpp:5071
bool HasNpcFlag(NPCFlags flags) const
Definition Unit.h:1096
uint32 GetArmor() const
Definition Unit.h:905
static void ApplyResilience(Unit const *victim, float *crit, int32 *damage, bool isCrit, CombatRating type)
Definition Unit.cpp:12032
float m_modMeleeHitChance
Definition Unit.h:1497
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition Unit.h:1518
void RemoveArenaAuras()
Definition Unit.cpp:4204
void _RemoveAllAuraStatMods()
Definition Unit.cpp:4347
void SetPhaseMask(uint32 newPhaseMask, bool update) override
Definition Unit.cpp:12152
uint32 GetAttackTime(WeaponAttackType att) const
Definition Unit.cpp:8471
ObjectGuid GetCritterGUID() const
Definition Unit.h:1249
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:890
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4792
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer)
Definition Unit.cpp:3845
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4445
void SetFullPower(Powers power)
Definition Unit.h:941
void StopAttackFaction(uint32 faction_id)
Definition Unit.cpp:13074
bool HasScheduledAIChange() const
Definition Unit.cpp:9584
uint32 GetCastingTimeForBonus(SpellInfo const *spellProto, DamageEffectType damagetype, uint32 CastingTime) const
Definition Unit.cpp:10659
void RemoveAreaAurasDueToLeaveWorld()
Definition Unit.cpp:4124
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition Unit.cpp:10811
bool IsRooted() const
Definition Unit.h:1168
bool CanModifyStats() const
Definition Unit.h:1531
void BuildMovementPacket(ByteBuffer *data) const
Definition Unit.cpp:12769
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition Unit.cpp:2709
void RemoveCharmedBy(Unit *charmer)
Definition Unit.cpp:11666
bool CreateVehicleKit(uint32 id, uint32 creatureEntry)
Definition Unit.cpp:11796
bool IsMounted() const
Definition Unit.h:1013
void _ApplyAura(AuraApplication *aurApp, uint8 effMask)
Definition Unit.cpp:3370
float GetSpeedRate(UnitMoveType mtype) const
Definition Unit.h:1654
virtual void SetDisplayId(uint32 modelId)
Definition Unit.cpp:10407
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, bool triggered, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:8858
std::set< Unit * > AttackerSet
Definition Unit.h:772
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3711
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3784
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition Unit.cpp:9650
void SetPowerType(Powers power, bool sendUpdate=true)
Definition Unit.cpp:5408
bool IsGuardian() const
Definition Unit.h:883
Unit * GetVictim() const
Definition Unit.h:859
void UpdatePetCombatState()
Definition Unit.cpp:8814
std::vector< Unit * > UnitVector
Definition Unit.h:774
bool IsMovedByServer() const
Definition Unit.h:1301
uint32 GetExtraUnitMovementFlags() const
Definition Unit.h:1685
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7606
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition Unit.cpp:12933
uint32 GetMeleeCritDamageReduction(uint32 damage) const
Definition Unit.h:1058
bool IsUnderWater() const
Definition Unit.cpp:3167
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition Unit.cpp:8678
void AddExtraAttacks(uint32 count)
Definition Unit.cpp:2131
void RemovePlayerFromVision(Player *player)
Definition Unit.cpp:6369
void SendFlightSplineSyncUpdate()
Definition Unit.cpp:571
void EnergizeBySpell(Unit *victim, uint32 spellId, int32 damage, Powers powerType)
Definition Unit.cpp:6440
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7639
float GetCreateStat(Stats stat) const
Definition Unit.h:1456
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition Unit.cpp:13777
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition Unit.cpp:10158
void UpdateSplinePosition()
Definition Unit.cpp:547
void SetOwnerGUID(ObjectGuid owner)
Definition Unit.cpp:5840
DeathState getDeathState() const
Definition Unit.h:1238
Unit * GetFirstControlled() const
Definition Unit.cpp:6239
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4822
void AddComboPoints(Unit *target, int8 count)
Definition Unit.cpp:10461
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11856
bool m_aiLocked
Definition Unit.h:1957
void ApplyCastTimePercentMod(float val, bool apply)
Definition Unit.cpp:10647
int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4912
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition Unit.cpp:5044
bool IsCritter() const
Definition Unit.h:1117
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1433
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const &casterGuid) const
Definition Unit.cpp:12091
void UpdateResistanceBuffModsMod(SpellSchools school)
Definition Unit.cpp:4932
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
Definition Unit.cpp:8142
uint32 GetSpellDamageReduction(uint32 damage) const
Definition Unit.h:1065
bool IsMagnet() const
Definition Unit.cpp:6212
void FinishSpell(CurrentSpellTypes spellType, bool ok=true)
Definition Unit.cpp:3051
std::unordered_set< AbstractFollower * > m_followingMe
Definition Unit.h:1959
virtual void Update(uint32 time) override
Definition Unit.cpp:432
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:11892
void UnsummonAllTotems()
Definition Unit.cpp:6392
GameObjectList m_gameObj
Definition Unit.h:1860
AuraMap m_ownedAuras
Definition Unit.h:1866
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition Unit.cpp:3172
Unit(bool isWorldObject)
Definition Unit.cpp:302
bool IsInFeralForm() const
Definition Unit.cpp:8969
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5038
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:9344
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7257
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition Unit.h:778
void RemoveUnitMovementFlag(uint32 f)
Definition Unit.h:1677
void RemoveBindSightAuras()
Definition Unit.cpp:6379
AuraApplicationMap m_appliedAuras
Definition Unit.h:1867
void HandleEmoteCommand(Emote emoteId)
Definition Unit.cpp:1568
CharmInfo * InitCharmInfo()
Definition Unit.cpp:9730
void RemoveAllAttackers()
Definition Unit.cpp:5736
void SetClass(uint8 classId)
Definition Unit.h:896
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13250
virtual bool CanSwim() const
Definition Unit.cpp:12818
virtual float GetNativeObjectScale() const
Definition Unit.h:1580
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition Unit.cpp:4683
void RemoveFromWorld() override
Definition Unit.cpp:9601
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications=false)
Definition Unit.cpp:13787
void SetVisibleAura(uint8 slot, AuraApplication *aurApp)
Definition Unit.cpp:648
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition Unit.cpp:2071
Player * GetCharmerOrSelfPlayer() const
Definition Unit.h:1296
void ScheduleAIChange()
Definition Unit.cpp:9555
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition Unit.h:880
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition Unit.cpp:9084
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition Unit.cpp:3552
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition Unit.cpp:5253
void ClearInCombat()
Definition Unit.h:1147
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:12576
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:634
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
bool isDying() const
Definition Unit.h:1235
float GetStat(Stats stat) const
Definition Unit.h:903
void SendMeleeAttackStop(Unit *victim=nullptr)
Definition Unit.cpp:2342
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage, uint8 damageIndex) const =0
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4852
void RemoveAllAuras()
Definition Unit.cpp:4157
SpellHistory * GetSpellHistory()
Definition Unit.h:1484
void IncrDiminishing(SpellInfo const *auraSpellInfo, bool triggered)
Definition Unit.cpp:8847
float m_modAttackSpeedPct[MAX_ATTACK]
Definition Unit.h:1502
bool IsControlledByPlayer() const
Definition Unit.h:1258
Unit * m_charmer
Definition Unit.h:1887
void RestoreDisplayId()
Definition Unit.cpp:10415
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:8834
bool m_canDualWield
Definition Unit.h:848
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1252
Minion * GetFirstMinion() const
Definition Unit.cpp:5878
UnitStandStateType GetStandState() const
Definition Unit.h:1001
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7478
UnitAI * GetScheduledChangeAI()
Definition Unit.cpp:9576
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition Unit.cpp:4573
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition Unit.cpp:683
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:11489
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition Unit.cpp:8477
void SetPetGUID(ObjectGuid guid)
Definition Unit.h:1248
AuraEffect * GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
Definition Unit.cpp:4415
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13423
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster, bool triggered) const
Definition Unit.cpp:4619
virtual void setDeathState(DeathState s)
Definition Unit.cpp:8728
void SetMaxHealth(uint32 val)
Definition Unit.cpp:9393
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1244
void GetPartyMembers(std::list< Unit * > &units)
Definition Unit.cpp:11911
virtual void AtEngage(Unit *target)
Definition Unit.cpp:8785
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:10930
ObjectGuid LastCharmerGUID
Definition Unit.h:1732
uint32 GetPower(Powers power) const
Definition Unit.h:934
uint32 m_interruptMask
Definition Unit.h:1876
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition Unit.cpp:12233
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5691
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2572
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1576
int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4922
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition Unit.cpp:9018
CombatManager & GetCombatManager()
Definition Unit.h:1130
uint32 GetMeleeDamageReduction(uint32 damage) const
Definition Unit.h:1063
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition Unit.cpp:2146
uint32 GetCreatureTypeMask() const
Definition Unit.cpp:8958
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition Unit.cpp:10900
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition Unit.cpp:4582
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4564
void SetCritterGUID(ObjectGuid guid)
Definition Unit.h:1250
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1338
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:787
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4069
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:835
void InitStatBuffMods()
Definition Unit.cpp:4961
int32 m_procDeep
Definition Unit.h:1854
int32 GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4892
void ClearDiminishings()
Definition Unit.cpp:8934
void SetPetNumberForClient(uint32 petNumber)
Definition Unit.h:1290
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData)
Definition Unit.cpp:3179
VisibleAuraMap m_visibleAuras
Definition Unit.h:1883
uint32 GetCreateMana() const
Definition Unit.h:1452
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition Unit.cpp:5083
bool IsServiceProvider() const
Definition Unit.cpp:8283
bool IsTotem() const
Definition Unit.h:886
CombatManager m_combatManager
Definition Unit.h:1948
void ChangeSeat(int8 seatId, bool next=true)
Definition Unit.cpp:12629
void SetInFront(WorldObject const *target)
Definition Unit.cpp:13244
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition Unit.cpp:8917
AuraStateAurasMap m_auraStateAuras
Definition Unit.h:1875
int32 GetResistance(SpellSchools school) const
Definition Unit.h:908
float m_speed_rate[MAX_MOVE_TYPE]
Definition Unit.h:1885
AuraList & GetSingleCastAuras()
Definition Unit.h:1386
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition Unit.cpp:8497
uint32 GetMovementCounterAndInc()
Definition Unit.h:1772
void SetModCastingSpeed(float castingSpeed)
Definition Unit.h:950
Vehicle * GetVehicleKit() const
Definition Unit.h:1735
void PushAI(UnitAI *newAI)
Definition Unit.cpp:9524
float m_modSpellHitChance
Definition Unit.h:1499
void ValidateAttackersAndOwnTarget()
Definition Unit.cpp:5673
Guardian * GetGuardianPet() const
Definition Unit.cpp:5894
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:598
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition Unit.cpp:13826
virtual bool IsEngaged() const
Definition Unit.h:1126
uint32 MeleeDamageBonusDone(Unit *pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:7871
AuraEffectList m_modAuras[TOTAL_AURAS]
Definition Unit.h:1872
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition Unit.cpp:3356
void DeMorph()
Definition Unit.cpp:3208
void RemoveAllMinionsByEntry(uint32 entry)
Definition Unit.cpp:6074
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId) const
-------—Pet responses methods--------------—
Definition Unit.cpp:10256
AuraMap & GetOwnedAuras()
Definition Unit.h:1328
void UpdateAllDamagePctDoneMods()
Definition Unit.cpp:9223
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:6987
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition Unit.cpp:13849
bool IsFalling() const
Definition Unit.cpp:12813
bool AttackStop()
Definition Unit.cpp:5645
void KnockbackFrom(float x, float y, float speedXY, float speedZ)
Definition Unit.cpp:12204
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3116
void RemoveAurasOnEvade()
Definition Unit.cpp:4218
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9066
void SetShapeshiftForm(ShapeshiftForm form)
Definition Unit.cpp:8964
void GetAllMinionsByEntry(std::list< Creature * > &Minions, uint32 entry)
Definition Unit.cpp:6062
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition Unit.cpp:2780
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:11873
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]
Definition Unit.h:1487
uint32 GetCreatePowerValue(Powers power) const
Definition Unit.cpp:9487
bool m_cleanupDone
Definition Unit.h:1969
static void DealDamageMods(Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:706
SharedVisionList m_sharedVision
Definition Unit.h:1890
ObjectGuid GetTarget() const
Definition Unit.h:1797
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition Unit.h:1974
uint8 GetLevel() const
Definition Unit.h:889
void SetMountDisplayId(uint32 mountDisplayId)
Definition Unit.h:1015
uint8 GetRace() const
Definition Unit.h:892
void RemoveCharmAuras()
Definition Unit.cpp:6384
bool IsInCombat() const
Definition Unit.h:1144
bool IsWalking() const
Definition Unit.h:1219
bool IsSitState() const
Definition Unit.cpp:10348
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9312
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition Unit.cpp:12239
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition Unit.cpp:518
uint32 GetDamageImmunityMask() const
Definition Unit.cpp:7791
bool HasPendingMovementChange() const
Definition Unit.h:1776
Player * GetControllingPlayer() const
Definition Unit.cpp:5865
float GetWeaponProcChance() const
Definition Unit.cpp:8159
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition Unit.cpp:3213
ObjectGuid GetPetGUID() const
Definition Unit.h:1247
uint32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype) const
Definition Unit.cpp:6910
uint32 m_lastManaUse
Definition Unit.h:1942
void UpdateStatBuffMod(Stats stat)
Definition Unit.cpp:4969
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12661
void SendPetDismissSound() const
Definition Unit.cpp:10276
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition Unit.h:1879
uint32 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition Unit.h:1019
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:5710
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1476
void DestroyForPlayer(Player *target, bool onDeath) const override
Definition Unit.cpp:13738
bool BuildPacket(WorldPacket *packet)
void SetBit(uint32 bit)
Definition UpdateMask.h:81
void AppendToPacket(ByteBuffer *data)
Definition UpdateMask.h:87
bool GetBit(uint32 index) const
Definition UpdateMask.h:40
Unit * GetBase() const
May be called from scripts.
Definition Vehicle.h:45
VehicleEntry const * GetVehicleInfo() const
Definition Vehicle.h:46
Vehicle * RemovePassenger(Unit *passenger)
Removes the passenger from the vehicle.
Definition Vehicle.cpp:497
bool AddPassenger(Unit *passenger, int8 seatId=-1)
Attempts to add a passenger to the vehicle on 'seatId'.
Definition Vehicle.cpp:426
uint32 GetCreatureEntry() const
Definition Vehicle.h:47
void Uninstall()
Removes all passengers and sets status to STATUS_UNINSTALLING. No new passengers can be added to the ...
Definition Vehicle.cpp:108
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition Vehicle.cpp:554
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition Vehicle.h:63
std::string GetDebugInfo() const
Definition Vehicle.cpp:969
SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const
Gets the next empty seat based on current seat.
Definition Vehicle.cpp:319
VehicleSeatAddon const * GetSeatAddonForSeatOfPassenger(Unit const *passenger) const
Gets the vehicle seat addon data for the seat of a passenger.
Definition Vehicle.cpp:360
Milliseconds GetDespawnDelay()
Definition Vehicle.cpp:961
void InstallAllAccessories(bool evading)
Definition Vehicle.cpp:84
uint32 GetMapId() const
Definition Position.h:193
int8 GetTransSeat() const
Definition Object.h:571
virtual void SetPhaseMask(uint32 newPhaseMask, bool update)
Definition Object.cpp:3417
uint32 GetPhaseMask() const
Definition Object.h:368
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition Object.cpp:1167
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1783
Map * GetMap() const
Definition Object.h:449
ZLiquidStatus GetLiquidStatus() const
Definition Object.h:378
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:1416
void AddToWorld() override
Definition Object.cpp:1060
Unit * GetCharmerOrOwner() const
Definition Object.cpp:2185
void RemoveFromWorld() override
Definition Object.cpp:1066
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
virtual uint8 GetLevelForTarget(WorldObject const *) const
Definition Object.h:423
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:2620
Unit * GetCharmerOrOwnerOrSelf() const
Definition Object.cpp:2195
virtual bool IsAlwaysDetectableFor(WorldObject const *) const
Definition Object.h:627
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
std::string GetDebugInfo() const override
Definition Object.cpp:3614
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2856
bool IsHostileTo(WorldObject const *target) const
Definition Object.cpp:2796
Unit * GetOwner() const
Definition Object.cpp:2180
ZoneScript * GetZoneScript() const
Definition Object.h:455
uint32 GetInstanceId() const
Definition Object.h:365
void setActive(bool isActiveObject)
Definition Object.cpp:991
bool InSamePhase(uint32 phasemask) const
Definition Object.h:369
float GetFloorZ() const
Definition Object.cpp:3586
std::string const & GetName() const
Definition Object.h:382
virtual void Heartbeat()
Definition Object.h:629
virtual bool IsAlwaysVisibleFor(WorldObject const *) const
Definition Object.h:624
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1226
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition Object.cpp:1049
void GetContactPoint(WorldObject const *obj, float &x, float &y, float &z, float distance2d=CONTACT_DISTANCE) const
Definition Object.cpp:3271
Transport * GetTransport() const
Definition Object.h:564
void UpdatePositionData()
Definition Object.cpp:1042
Player * GetSpellModOwner() const
Definition Object.cpp:2223
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:2203
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition Object.cpp:972
void AddToNotify(uint16 f)
Definition Object.h:546
EventProcessor m_Events
Definition Object.h:591
float GetVisibilityRange() const
Definition Object.cpp:1492
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition Object.cpp:2571
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:1123
uint32 GetZoneId() const
Definition Object.h:373
MovementInfo m_movementInfo
Definition Object.h:575
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition Object.h:444
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2801
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:1160
virtual void Update(uint32 diff)
Definition Object.cpp:960
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition Object.cpp:2634
int32 CalculateSpellDamage(SpellEffectInfo const &spellEffectInfo, int32 const *basePoints=nullptr) const
Definition Object.cpp:2248
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3482
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:1031
void Initialize(uint16 opcode, size_t newres=200)
Definition WorldPacket.h:73
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > ModelPosition
Definition PetPackets.h:130
WorldPacket const * Write() override
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
LocaleConstant GetSessionDbLocaleIndex() const
void KickPlayer(std::string const &reason)
Kick a player out of the World.
Definition Util.h:412
Opcodes
Definition Opcodes.h:29
@ SMSG_PET_UPDATE_COMBO_POINTS
Definition Opcodes.h:1199
@ SMSG_SPELLENERGIZELOG
Definition Opcodes.h:366
@ SMSG_MOVE_LAND_WALK
Definition Opcodes.h:252
@ SMSG_SPLINE_MOVE_STOP_SWIM
Definition Opcodes.h:809
@ SMSG_PARTYKILLLOG
Definition Opcodes.h:530
@ MSG_MOVE_HOVER
Definition Opcodes.h:276
@ SMSG_MOVE_FEATHER_FALL
Definition Opcodes.h:271
@ SMSG_MOVE_SET_HOVER
Definition Opcodes.h:273
@ SMSG_SPLINE_MOVE_LAND_WALK
Definition Opcodes.h:807
@ SMSG_SPLINE_MOVE_START_SWIM
Definition Opcodes.h:808
@ SMSG_SPLINE_MOVE_SET_RUN_MODE
Definition Opcodes.h:810
@ MSG_MOVE_ROOT
Definition Opcodes.h:265
@ SMSG_MOVE_WATER_WALK
Definition Opcodes.h:251
@ SMSG_SPLINE_MOVE_GRAVITY_DISABLE
Definition Opcodes.h:1264
@ SMSG_SPELLORDAMAGE_IMMUNE
Definition Opcodes.h:640
@ SMSG_FORCE_MOVE_UNROOT
Definition Opcodes.h:263
@ MSG_MOVE_UPDATE_CAN_FLY
Definition Opcodes.h:970
@ SMSG_MOVE_KNOCK_BACK
Definition Opcodes.h:268
@ SMSG_SPELLNONMELEEDAMAGELOG
Definition Opcodes.h:621
@ SMSG_PROCRESIST
Definition Opcodes.h:637
@ SMSG_BREAK_TARGET
Definition Opcodes.h:367
@ MSG_MOVE_WATER_WALK
Definition Opcodes.h:718
@ SMSG_MOVE_GRAVITY_DISABLE
Definition Opcodes.h:1259
@ SMSG_LOOT_LIST
Definition Opcodes.h:1046
@ SMSG_FORCE_MOVE_ROOT
Definition Opcodes.h:261
@ SMSG_MOVE_GRAVITY_ENABLE
Definition Opcodes.h:1261
@ SMSG_PLAYER_VEHICLE_DATA
Definition Opcodes.h:1220
@ SMSG_MOVE_NORMAL_FALL
Definition Opcodes.h:272
@ SMSG_SPLINE_MOVE_SET_HOVER
Definition Opcodes.h:804
@ SMSG_UPDATE_COMBO_POINTS
Definition Opcodes.h:954
@ SMSG_SPLINE_MOVE_SET_FLYING
Definition Opcodes.h:1087
@ SMSG_SPELLDAMAGESHIELD
Definition Opcodes.h:620
@ SMSG_SPLINE_MOVE_UNSET_HOVER
Definition Opcodes.h:805
@ MSG_MOVE_TELEPORT
Definition Opcodes.h:226
@ SMSG_SPLINE_MOVE_UNROOT
Definition Opcodes.h:801
@ MSG_MOVE_FEATHER_FALL
Definition Opcodes.h:717
@ MSG_MOVE_TELEPORT_ACK
Definition Opcodes.h:228
@ SMSG_SPLINE_MOVE_NORMAL_FALL
Definition Opcodes.h:803
@ SMSG_MOVE_UNSET_HOVER
Definition Opcodes.h:274
@ SMSG_DISMOUNT
Definition Opcodes.h:969
@ SMSG_MOVE_SET_CAN_FLY
Definition Opcodes.h:864
@ SMSG_SPELLHEALLOG
Definition Opcodes.h:365
@ SMSG_SPLINE_MOVE_FEATHER_FALL
Definition Opcodes.h:802
@ SMSG_SPLINE_MOVE_ROOT
Definition Opcodes.h:823
@ SMSG_ATTACKERSTATEUPDATE
Definition Opcodes.h:359
@ SMSG_SPLINE_MOVE_SET_WALK_MODE
Definition Opcodes.h:811
@ SMSG_SPLINE_MOVE_GRAVITY_ENABLE
Definition Opcodes.h:1265
@ SMSG_SPLINE_MOVE_UNSET_FLYING
Definition Opcodes.h:1088
@ SMSG_AI_REACTION
Definition Opcodes.h:345
@ SMSG_MOVE_UNSET_CAN_FLY
Definition Opcodes.h:865
@ MSG_MOVE_UNROOT
Definition Opcodes.h:266
@ SMSG_STANDSTATE_UPDATE
Definition Opcodes.h:698
@ MSG_MOVE_GRAVITY_CHNG
Definition Opcodes.h:1263
@ SMSG_POWER_UPDATE
Definition Opcodes.h:1181
@ SMSG_PERIODICAURALOG
Definition Opcodes.h:619
@ SMSG_SPLINE_MOVE_WATER_WALK
Definition Opcodes.h:806
#define sWorld
Definition World.h:900
@ CONFIG_PENDING_MOVE_CHANGES_TIMEOUT
Definition World.h:403
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition World.h:289
@ RATE_POWER_RAGE_INCOME
Definition World.h:412
@ RATE_DURABILITY_LOSS_DAMAGE
Definition World.h:467
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition World.h:466
@ CONFIG_LISTEN_RANGE_YELL
Definition World.h:191
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:189
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition World.h:190
@ CONFIG_DURABILITY_LOSS_IN_PVP
Definition World.h:91
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition World.h:98
TimePoint Now()
Current chrono steady_clock time point.
Definition GameTime.cpp:57
time_t GetGameTime()
Definition GameTime.cpp:42
uint32 GetGameTimeMS()
Definition GameTime.cpp:47
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
auto MapEqualRange(M &map, typename M::key_type const &key)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition Containers.h:108
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:56
bool IsValidMapCoord(float c)
ObjectGuid CasterGUID
int32 const * BaseAmount
ObjectGuid CastItemGUID
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCaster(Unit *caster)
uint8 GetAuraEffectMask() const
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
SpellInfo const * GetSpellInfo() const
std::string const & GetText(LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false) const
Definition ObjectMgr.h:496
WeaponAttackType AttackType
Definition Unit.h:556
uint32 DamageSchoolMask
Definition Unit.h:545
uint32 ProcVictim
Definition Unit.h:558
struct CalcDamageInfo::@227 Damages[2]
Unit * Target
Definition Unit.h:541
uint32 TargetState
Definition Unit.h:553
uint32 ProcAttacker
Definition Unit.h:557
MeleeHitOutcome HitOutCome
Definition Unit.h:560
Unit * Attacker
Definition Unit.h:540
uint32 Damage
Definition Unit.h:546
uint32 Blocked
Definition Unit.h:551
uint32 Resist
Definition Unit.h:548
uint32 CleanDamage
Definition Unit.h:559
uint32 HitInfo
Definition Unit.h:552
uint32 Absorb
Definition Unit.h:547
CastSpellExtraArgs & AddSpellBP0(int32 val)
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
ObjectGuid OriginalCaster
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:192
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
void RestoreState()
Definition Unit.cpp:9765
void SaveStayPosition()
Definition Unit.cpp:13193
CharmInfo(Unit *unit)
Definition Unit.cpp:9748
float _stayY
Definition Unit.h:736
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13183
bool IsCommandAttack()
Definition Unit.cpp:13178
void LoadPetActionBar(const std::string &data)
Definition Unit.cpp:9952
void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
Definition Unit.h:696
bool _isAtStay
Definition Unit.h:732
bool AddSpellToActionBar(SpellInfo const *spellInfo, ActiveStates newstate=ACT_DECIDE, uint8 preferredSlot=0)
Definition Unit.cpp:9882
void InitPossessCreateSpells()
Definition Unit.cpp:9796
void SetIsAtStay(bool val)
Definition Unit.cpp:13214
bool IsFollowing()
Definition Unit.cpp:13229
float _stayX
Definition Unit.h:735
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition Unit.cpp:9943
float _stayZ
Definition Unit.h:737
bool IsReturning()
Definition Unit.cpp:13239
void SetIsFollowing(bool val)
Definition Unit.cpp:13224
void InitPetActionBar()
Definition Unit.cpp:9771
bool _isCommandFollow
Definition Unit.h:731
UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX]
Definition Unit.h:722
~CharmInfo()
Definition Unit.cpp:9763
void SetIsReturning(bool val)
Definition Unit.cpp:13234
void InitCharmCreateSpells()
Definition Unit.cpp:9832
void BuildActionBar(WorldPacket *data)
Definition Unit.cpp:9983
bool RemoveSpellFromActionBar(uint32 spell_id)
Definition Unit.cpp:9914
void SetSpellAutocast(SpellInfo const *spellInfo, bool state)
Definition Unit.cpp:9989
bool IsAtStay()
Definition Unit.cpp:13219
bool _isFollowing
Definition Unit.h:733
bool _isCommandAttack
Definition Unit.h:730
void GetStayPosition(float &x, float &y, float &z)
Definition Unit.cpp:13207
ReactStates _oldReactState
Definition Unit.h:728
void ToggleCreatureAutocast(SpellInfo const *spellInfo, bool apply)
Definition Unit.cpp:9933
bool IsCommandFollow()
Definition Unit.cpp:13188
void InitEmptyActionBar(bool withAttack=true)
Definition Unit.cpp:9786
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13173
bool _isReturning
Definition Unit.h:734
Unit * _unit
Definition Unit.h:721
uint32 _petnumber
Definition Unit.h:725
CharmSpellInfo _charmspells[4]
Definition Unit.h:723
bool HasFlag(ChrRacesFlags flag) const
uint32 CreatureType
MeleeHitOutcome hitOutCome
Definition Unit.h:423
uint32 absorbed_damage
Definition Unit.h:419
WeaponAttackType attackType
Definition Unit.h:422
bool HasFlag(CreatureModelDataFlags flag) const
uint32 GetFirstVisibleModel() const
Definition Creature.cpp:152
uint32 hitCount
Definition Unit.h:389
uint32 hitTime
Definition Unit.h:388
uint16 stack
Definition Unit.h:387
bool IsFriendlyTo(FactionTemplateEntry const &entry) const
Definition Loot.h:207
bool empty() const
Definition Loot.h:238
bool isLooted() const
Definition Loot.h:239
void clear()
Definition Loot.cpp:148
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT)
Definition Loot.cpp:220
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition Loot.cpp:465
uint16 GetExtraMovementFlags() const
struct MovementInfo::JumpInfo jump
void RemoveMovementFlag(uint32 flag)
uint32 fallTime
struct MovementInfo::TransportInfo transport
float splineElevation
bool HasMovementFlag(uint32 flag) const
uint32 GetMovementFlags() const
void SetFallTime(uint32 val)
bool HasExtraMovementFlag(uint16 flag) const
Position pos
MovementChangeType movementChangeType
Definition Unit.h:306
Optional< LiquidData > liquidInfo
Definition MapDefines.h:113
float m_positionZ
Definition Position.h:58
float GetExactDist2d(const float x, const float y) const
Definition Position.h:109
float GetRelativeAngle(float x, float y) const
Definition Position.h:139
std::string ToString() const
Definition Position.cpp:149
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:120
float GetAbsoluteAngle(float x, float y) const
Definition Position.h:128
void GetSinCos(float x, float y, float &vsin, float &vcos) const
Definition Position.cpp:67
void SetOrientation(float orientation)
Definition Position.h:74
Position GetPosition() const
Definition Position.h:87
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80
void RelocateOffset(Position const &offset)
Definition Position.cpp:36
void Relocate(float x, float y)
Definition Position.h:66
Unit * attacker
Definition Unit.h:572
uint32 schoolMask
Definition Unit.h:576
uint32 cleanDamage
Definition Unit.h:584
AuraEffect const * auraEff
Definition Unit.h:593
void SetActionAndType(uint32 action, ActiveStates type)
Definition Unit.h:634
bool IsActionBarForSpell() const
Definition Unit.h:628
void SetType(ActiveStates type)
Definition Unit.h:639
void SetAction(uint32 action)
Definition Unit.h:644
uint32 GetAction() const
Definition Unit.h:627
VehicleExitParameters ExitParameter