TrinityCore
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 "BattlePetMgr.h"
26#include "CellImpl.h"
27#include "CharacterCache.h"
28#include "CharmInfo.h"
29#include "ChatPackets.h"
30#include "ChatTextBuilder.h"
31#include "CombatLogPackets.h"
32#include "CombatPackets.h"
33#include "Common.h"
34#include "ConditionMgr.h"
35#include "Containers.h"
36#include "Creature.h"
37#include "CreatureAI.h"
38#include "CreatureAIImpl.h"
39#include "CreatureAIFactory.h"
40#include "CreatureGroups.h"
41#include "DB2Stores.h"
42#include "Formulas.h"
43#include "GameObjectAI.h"
44#include "GameTime.h"
45#include "GridNotifiersImpl.h"
46#include "Group.h"
47#include "InstanceScript.h"
48#include "Item.h"
49#include "ItemBonusMgr.h"
50#include "KillRewarder.h"
51#include "ListUtils.h"
52#include "Log.h"
53#include "Loot.h"
54#include "LootMgr.h"
55#include "LootPackets.h"
56#include "MiscPackets.h"
57#include "MotionMaster.h"
58#include "MovementGenerator.h"
59#include "MovementPackets.h"
60#include "MoveSpline.h"
61#include "MoveSplineInit.h"
62#include "ObjectAccessor.h"
63#include "ObjectMgr.h"
64#include "Opcodes.h"
65#include "OutdoorPvP.h"
66#include "PartyPackets.h"
67#include "Pet.h"
68#include "PetPackets.h"
69#include "PhasingHandler.h"
70#include "Player.h"
71#include "PlayerAI.h"
72#include "QuestDef.h"
73#include "Spell.h"
74#include "ScheduledChangeAI.h"
75#include "SpellAuraEffects.h"
76#include "SpellAuras.h"
77#include "SpellHistory.h"
78#include "SpellInfo.h"
79#include "SpellMgr.h"
80#include "SpellPackets.h"
81#include "StringConvert.h"
82#include "TemporarySummon.h"
83#include "Totem.h"
84#include "Transport.h"
85#include "Util.h"
86#include "Vehicle.h"
87#include "VehiclePackets.h"
88#include "Vignette.h"
89#include "VignettePackets.h"
90#include "World.h"
91#include "WorldPacket.h"
92#include "WorldSession.h"
93#include <queue>
94#include <sstream>
95#include <cmath>
96
98{
99 2.5f, // MOVE_WALK
100 7.0f, // MOVE_RUN
101 4.5f, // MOVE_RUN_BACK
102 4.722222f, // MOVE_SWIM
103 2.5f, // MOVE_SWIM_BACK
104 3.141594f, // MOVE_TURN_RATE
105 7.0f, // MOVE_FLIGHT
106 4.5f, // MOVE_FLIGHT_BACK
107 3.14f // MOVE_PITCH_RATE
108};
109
111{
112 2.5f, // MOVE_WALK
113 7.0f, // MOVE_RUN
114 4.5f, // MOVE_RUN_BACK
115 4.722222f, // MOVE_SWIM
116 2.5f, // MOVE_SWIM_BACK
117 3.141594f, // MOVE_TURN_RATE
118 7.0f, // MOVE_FLIGHT
119 4.5f, // MOVE_FLIGHT_BACK
120 3.14f // MOVE_PITCH_RATE
121};
122
123DispelableAura::DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
124 _aura(aura), _chance(dispelChance), _charges(dispelCharges)
125{
126}
127
129
131{
132 return roll_chance_i(_chance);
133}
134
135DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
136 : m_attacker(attacker), m_victim(victim), m_damage(damage), m_originalDamage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
137 m_absorb(0), m_resist(0), m_block(0), m_hitMask(PROC_HIT_NONE)
138{
139}
140
142 : m_attacker(dmgInfo.Attacker), m_victim(dmgInfo.Target), m_damage(dmgInfo.Damage), m_originalDamage(dmgInfo.Damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.DamageSchoolMask)),
143 m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.AttackType), m_absorb(dmgInfo.Absorb), m_resist(dmgInfo.Resist), m_block(dmgInfo.Blocked), m_hitMask(PROC_HIT_NONE)
144{
145 switch (dmgInfo.TargetState)
146 {
149 break;
152 break;
153 }
154
157
158 if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
160
161 if (m_block)
163
164 bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
166 switch (dmgInfo.HitOutCome)
167 {
168 case MELEE_HIT_MISS:
170 break;
171 case MELEE_HIT_DODGE:
173 break;
174 case MELEE_HIT_PARRY:
176 break;
177 case MELEE_HIT_EVADE:
179 break;
180 case MELEE_HIT_BLOCK:
183 case MELEE_HIT_NORMAL:
184 if (!damageNullified)
186 break;
187 case MELEE_HIT_CRIT:
188 if (!damageNullified)
190 break;
191 }
192}
193
194DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, ProcFlagsHit hitMask)
195 : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_originalDamage(spellNonMeleeDamage.originalDamage),
196 m_spellInfo(spellNonMeleeDamage.Spell), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
197 m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
198{
199 if (spellNonMeleeDamage.blocked)
201 if (spellNonMeleeDamage.absorb)
203}
204
206{
207 amount = std::max(amount, -static_cast<int32>(GetDamage()));
208 m_damage += amount;
209}
210
212{
213 amount = std::min(amount, GetDamage());
214 m_absorb += amount;
215 m_damage -= amount;
217}
218
220{
221 amount = std::min(amount, GetDamage());
222 m_resist += amount;
223 m_damage -= amount;
224 if (!m_damage)
225 {
228 }
229}
230
232{
233 amount = std::min(amount, GetDamage());
234 m_block += amount;
235 m_damage -= amount;
237 if (!m_damage)
238 {
241 }
242}
243
245{
246 return m_hitMask;
247}
248
249HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
250 : _healer(healer), _target(target), _heal(heal), _originalHeal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
251{
252}
253
255{
256 amount = std::min(amount, GetHeal());
257 _absorb += amount;
258 _heal -= amount;
259 amount = std::min(amount, GetEffectiveHeal());
260 _effectiveHeal -= amount;
262}
263
265{
266 return _hitMask;
267}
268
269ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
270 ProcFlagsInit const& typeMask, ProcFlagsSpellType spellTypeMask,
271 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
272 Spell* spell, DamageInfo* damageInfo,
273 HealInfo* healInfo) :
274 _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget),
275 _typeMask(typeMask), _spellTypeMask(spellTypeMask),
276 _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell),
277 _damageInfo(damageInfo), _healInfo(healInfo)
278{ }
279
281{
282 if (_spell)
283 return _spell->GetSpellInfo();
284 if (_damageInfo)
285 return _damageInfo->GetSpellInfo();
286 if (_healInfo)
287 return _healInfo->GetSpellInfo();
288 return nullptr;
289}
290
292{
293 if (_spell)
294 return _spell->GetSpellInfo()->GetSchoolMask();
295 if (_damageInfo)
296 return _damageInfo->GetSchoolMask();
297 if (_healInfo)
298 return _healInfo->GetSchoolMask();
300}
301
302SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId)
303 : target(_target), attacker(_attacker), castId(_castId), Spell(_spellInfo), SpellVisual(spellVisual), damage(0), originalDamage(0),
304 schoolMask(_schoolMask), absorb(0), resist(0), periodicLog(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false), preHitHealth(_target->GetHealth())
305{
306}
307
308Unit::Unit(bool isWorldObject) :
309 WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(std::make_unique<Movement::MoveSpline>()),
310 m_ControlledByPlayer(false), m_procDeep(0), m_procChainLength(0), m_transformSpell(0),
311 m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
312 m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
313 i_motionMaster(std::make_unique<MotionMaster>(this)), m_regenTimer(0), m_vehicle(nullptr),
314 m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
315 m_threatManager(this), m_aiLocked(false), _playHoverAnim(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
316 _spellHistory(std::make_unique<SpellHistory>(this))
317{
320
322
324
325 m_baseAttackSpeed = { };
326 m_attackTimer = { };
327 m_modAttackSpeedPct.fill(1.0f);
328
329 m_canDualWield = false;
330
332
333 m_state = 0;
335
336 m_currentSpells = { };
337
339
340 m_canModifyStats = false;
341
342 for (uint8 i = 0; i < UNIT_MOD_END; ++i)
343 {
349 }
350 // implement 50% base damage from offhand
352
353 for (uint8 i = 0; i < MAX_ATTACK; ++i)
354 {
357 }
358
359 m_createStats = { };
360 m_floatStatPosBuff = { };
361 m_floatStatNegBuff = { };
362
363 m_attacking = nullptr;
364 m_modMeleeHitChance = 0.0f;
366 m_modSpellHitChance = 0.0f;
368
369 m_speed_rate.fill(1.0f);
370 SetFlightCapabilityID(0, false);
371
372 // remove aurastates allowing special moves
373 m_reactiveTimer = { };
374
375 m_cleanupDone = false;
377
379
380 _lastLiquid = nullptr;
381
382 _oldFactionId = 0;
383 _isWalkingBeforeCharm = false;
384 _instantCast = false;
385 _isCombatDisallowed = false;
386
388}
389
391// Methods of class Unit
393{
394 // set current spells as deletable
395 for (size_t i = 0; i < m_currentSpells.size(); ++i)
396 {
397 if (m_currentSpells[i])
398 {
399 m_currentSpells[i]->SetReferencedFromCurrent(false);
400 m_currentSpells[i] = nullptr;
401 }
402 }
403
405
407
410 ASSERT(m_attackers.empty());
411 ASSERT(m_sharedVision.empty());
412 ASSERT(m_Controlled.empty());
413 ASSERT(m_appliedAuras.empty());
414 ASSERT(m_ownedAuras.empty());
415 ASSERT(m_removedAuras.empty());
416 ASSERT(m_dynObj.empty());
417 ASSERT(m_gameObj.empty());
418 ASSERT(m_areaTrigger.empty());
421}
422
424{
425 // WARNING! Order of execution here is important, do not change.
426 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
427 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
428 WorldObject::Update(p_time);
429
430 if (!IsInWorld())
431 return;
432
433 _UpdateSpells(p_time);
434
435 // If this is set during update SetCantProc(false) call is missing somewhere in the code
436 // Having this would prevent spells from being proced, so let's crash
438
439 m_combatManager.Update(p_time);
440
443 {
444 while (!extraAttacksTargets.empty())
445 {
446 auto itr = extraAttacksTargets.begin();
447 ObjectGuid targetGuid = itr->first;
448 uint32 count = itr->second;
449 extraAttacksTargets.erase(itr);
450 if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
451 HandleProcExtraAttackFor(victim, count);
452 }
454 }
455
456 auto spellPausesCombatTimer = [&](CurrentSpellTypes type)
457 {
459 };
460
461 if (!spellPausesCombatTimer(CURRENT_GENERIC_SPELL) && !spellPausesCombatTimer(CURRENT_CHANNELED_SPELL))
462 {
463 if (uint32 base_att = getAttackTimer(BASE_ATTACK))
464 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
465 if (uint32 off_att = getAttackTimer(OFF_ATTACK))
466 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
467 if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
468 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
469 }
470
471 // update abilities available only for fraction of time
472 UpdateReactives(p_time);
473
474 if (IsAlive())
475 {
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 // Trigger heartbeat procs and generic aura behavior such as food emotes and invoking aura script hooks
511
512 // Update Vignette position and visibility
513 if (m_vignette)
515}
516
518{
519 for (auto const& [_, auraApplication] : m_appliedAuras)
520 auraApplication->GetBase()->Heartbeat();
521
523}
524
526{
527 if (Player const* player = ToPlayer())
528 return player->GetWeaponForAttack(OFF_ATTACK, true) != nullptr;
529
530 return CanDualWield();
531}
532
533void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
534{
535 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
536 {
537 init.MoveTo(x, y, z, generatePath, forceDestination);
538 init.SetVelocity(speed);
539 };
541}
542
544{
545 switch (type)
546 {
548 if (GetMap()->IsRaid())
551 break;
556 break;
559 break;
560 default:
561 break;
562 }
563
564 if (IsAlive())
566}
567
569{
570 switch (type)
571 {
573 if (GetMap()->IsRaid())
576 break;
577 default:
578 break;
579 }
580
582 {
583 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(cooldown.SpellId, DIFFICULTY_NONE);
584
586 }, true);
587}
588
590{
591 if (movespline->Finalized())
592 return;
593
594 movespline->updateState(t_diff);
595 bool arrived = movespline->Finalized();
596
597 if (arrived)
598 {
600
601 if (Optional<AnimTier> animTier = movespline->GetAnimation())
602 SetAnimTier(*animTier);
603 }
604
606}
607
609{
610 Movement::Location loc = movespline->ComputePosition();
611
612 if (movespline->onTransport)
613 {
615 pos.m_positionX = loc.x;
616 pos.m_positionY = loc.y;
617 pos.m_positionZ = loc.z;
619
620 if (TransportBase* transport = GetDirectTransport())
621 transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
622 else
623 return;
624 }
625
628
629 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
630}
631
633{
634 if (!movespline->isCyclic() || movespline->Finalized())
635 return;
636
638 flightSplineSync.Guid = GetGUID();
639 flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
640 SendMessageToSet(flightSplineSync.Write(), true);
641}
642
644{
645 // TODO: Check if orientation transport offset changed instead of only global orientation
648
651}
652
654{
656 movespline->_Interrupt();
657}
658
660{
662}
663
664bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
665{
666 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
667 return false;
668
669 float dx = GetPositionX() - obj->GetPositionX();
670 float dy = GetPositionY() - obj->GetPositionY();
671 float dz = GetPositionZ() - obj->GetPositionZ();
672 float distsq = dx * dx + dy * dy + dz * dz;
673
674 float sizefactor = GetCombatReach() + obj->GetCombatReach();
675 float maxdist = dist2compare + sizefactor;
676
677 return distsq < maxdist * maxdist;
678}
679
680bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
681{
682 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
683 return false;
684
685 float dx = pos.GetPositionX() - obj->GetPositionX();
686 float dy = pos.GetPositionY() - obj->GetPositionY();
687 float dz = pos.GetPositionZ() - obj->GetPositionZ();
688 float distsq = dx*dx + dy*dy + dz*dz;
689
691
692 return distsq <= maxdist * maxdist;
693}
694
695float Unit::GetMeleeRange(Unit const* target) const
696{
697 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
698 return std::max(range, NOMINAL_MELEE_RANGE);
699}
700
701bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
702{
703 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
704 return false;
705
706 float objBoundaryRadius = std::max(obj->GetBoundingRadius(), MIN_MELEE_REACH);
707
708 return IsInDist(obj, objBoundaryRadius);
709}
710
712{
713 m_visibleAuras.insert(aurApp);
714 m_visibleAurasToUpdate.insert(aurApp);
716}
717
719{
720 m_visibleAuras.erase(aurApp);
721 m_visibleAurasToUpdate.erase(aurApp);
723}
724
726{
729 for (AuraApplication const* aurApp : m_interruptableAuras)
730 {
731 m_interruptMask |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags;
732 m_interruptMask2 |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags2;
733 }
734
736 {
737 if (spell->getState() == SPELL_STATE_CASTING)
738 {
739 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
740 m_interruptMask2 |= spell->m_spellInfo->ChannelInterruptFlags2;
741 }
742 }
743}
744
745bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
746{
747 for (AuraEffect const* aura : GetAuraEffectsByType(auraType))
748 if (aura->GetSpellInfo()->SpellFamilyName == familyName && aura->GetSpellInfo()->SpellFamilyFlags & familyFlags)
749 return true;
750 return false;
751}
752
754{
755 AuraEffectList const& auras = GetAuraEffectsByType(type);
756 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
757 if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
758 (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Damage))
759 return true;
760 return false;
761}
762
763bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const
764{
765 uint32 excludeAura = 0;
766 if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : nullptr)
767 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
768
775}
776
777/*static*/ void Unit::DealDamageMods(Unit const* attacker, Unit const* victim, uint32& damage, uint32* absorb)
778{
779 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
780 {
781 if (absorb)
782 *absorb += damage;
783 damage = 0;
784 return;
785 }
786
787 if (attacker)
788 damage *= attacker->GetDamageMultiplierForTarget(victim);
789}
790
792{
793 AuraEffectVector effects;
794 std::copy(list.begin(), list.end(), std::back_inserter(effects));
795 return effects;
796}
797
798/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
799{
800 uint32 damageDone = damage;
801 uint32 damageTaken = damage;
802 if (attacker)
803 damageTaken = damage / victim->GetHealthMultiplierForTarget(attacker);
804
805 // call script hooks
806 {
807 uint32 tmpDamage = damageTaken;
808
809 // sparring
810 if (Creature* victimCreature = victim->ToCreature())
811 tmpDamage = victimCreature->CalculateDamageForSparring(attacker, tmpDamage);
812
813 if (UnitAI* victimAI = victim->GetAI())
814 victimAI->DamageTaken(attacker, tmpDamage, damagetype, spellProto);
815
816 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
817 attackerAI->DamageDealt(victim, tmpDamage, damagetype);
818
819 // Hook for OnDamage Event
820 sScriptMgr->OnDamage(attacker, victim, tmpDamage);
821
822 // if any script modified damage, we need to also apply the same modification to unscaled damage value
823 if (tmpDamage != damageTaken)
824 {
825 if (attacker)
826 damageDone = tmpDamage * victim->GetHealthMultiplierForTarget(attacker);
827 else
828 damageDone = tmpDamage;
829
830 damageTaken = tmpDamage;
831 }
832 }
833
834 // Signal to pets that their owner was attacked - except when DOT.
835 if (attacker != victim && damagetype != DOT)
836 {
837 for (Unit* controlled : victim->m_Controlled)
838 if (Creature* cControlled = controlled->ToCreature())
839 if (CreatureAI* controlledAI = cControlled->AI())
840 controlledAI->OwnerAttackedBy(attacker);
841 }
842
843 if (Player* player = victim->ToPlayer())
844 if (player->GetCommandStatus(CHEAT_GOD))
845 return 0;
846
847 if (damagetype != NODAMAGE)
848 {
849 // interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras)
850 if (spellProto)
851 {
854 }
855 else
857
858 if (!damageTaken && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
859 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
860 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
861 if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb))
862 victim->InterruptNonMeleeSpells(false);
863
864 // We're going to call functions which can modify content of the list during iteration over it's elements
865 // Let's copy the list so we can prevent iterator invalidation
867 // copy damage to casters of this aura
868 for (auto i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
869 {
870 // Check if aura was removed during iteration - we don't need to work on such auras
871 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
872 continue;
873 // check damage school mask
874 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
875 continue;
876
877 Unit* shareDamageTarget = (*i)->GetCaster();
878 if (!shareDamageTarget)
879 continue;
880 SpellInfo const* spell = (*i)->GetSpellInfo();
881
882 uint32 share = CalculatePct(damageDone, (*i)->GetAmount());
883
885 Unit::DealDamageMods(attacker, shareDamageTarget, share, nullptr);
886 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
887 }
888 }
889
890 if (!damageDone)
891 return 0;
892
893 uint32 health = victim->GetHealth();
894
895 // duel ends when player has 1 or less hp
896 bool duel_hasEnded = false;
897 bool duel_wasMounted = false;
898 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damageTaken >= (health-1))
899 {
900 if (!attacker)
901 return 0;
902
903 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
904 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
905 damageTaken = health - 1;
906
907 duel_hasEnded = true;
908 }
909 else if (victim->IsCreature() && victim != attacker && damageTaken >= health && victim->ToCreature()->HasFlag(CREATURE_STATIC_FLAG_UNKILLABLE))
910 {
911 damageTaken = health - 1;
912
913 // If we had damage (aka health was not 1 already) trigger OnHealthDepleted
914 if (damageTaken > 0)
915 {
916 if (CreatureAI* victimAI = victim->ToCreature()->AI())
917 victimAI->OnHealthDepleted(attacker, false);
918 }
919 }
920 else if (victim->IsVehicle() && damageTaken >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
921 {
922 Player* victimRider = victim->GetCharmer()->ToPlayer();
923
924 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
925 {
926 if (!attacker)
927 return 0;
928
929 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
930 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
931 damageTaken = health - 1;
932
933 duel_wasMounted = true;
934 duel_hasEnded = true;
935 }
936 }
937
938 if (spellProto && spellProto->HasAttribute(SPELL_ATTR9_CANNOT_KILL_TARGET) && damageTaken >= health)
939 damageTaken = health - 1;
940
941 if (attacker && attacker != victim)
942 {
943 if (Player* killer = attacker->ToPlayer())
944 {
945 // in bg, count dmg if victim is also a player
946 if (victim->GetTypeId() == TYPEID_PLAYER && !(spellProto && spellProto->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD)))
947 if (Battleground* bg = killer->GetBattleground())
948 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damageDone);
949
950 killer->UpdateCriteria(CriteriaType::DamageDealt, health > damageDone ? damageDone : health, 0, 0, victim);
951 killer->UpdateCriteria(CriteriaType::HighestDamageDone, damageDone);
952 }
953 }
954
955 if (victim->GetTypeId() == TYPEID_PLAYER)
957
958 if (victim->GetTypeId() != TYPEID_PLAYER && (!victim->IsControlledByPlayer() || victim->IsVehicle()))
959 {
960 victim->ToCreature()->SetTappedBy(attacker);
961
962 if (!attacker || attacker->IsControlledByPlayer())
963 victim->ToCreature()->LowerPlayerDamageReq(health < damageTaken ? health : damageTaken);
964 }
965
966 bool killed = false;
967 bool skipSettingDeathState = false;
968
969 if (health <= damageTaken)
970 {
971 killed = true;
972
973 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
975
976 if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL))
977 {
979 DamageInfo damageInfo = DamageInfo(attacker, victim, damageTaken, spellProto, damageSchoolMask, damagetype,
980 cleanDamage ? cleanDamage->attackType : BASE_ATTACK);
981 for (AuraEffect* absorbAurEff : vAbsorbOverkill)
982 {
983 Aura* base = absorbAurEff->GetBase();
984 AuraApplication const* aurApp = base->GetApplicationOfTarget(victim->GetGUID());
985 if (!aurApp)
986 continue;
987
988 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
989 continue;
990
991 // cannot absorb over limit
992 if (damageTaken >= victim->CountPctFromMaxHealth(100 + absorbAurEff->GetMiscValueB()))
993 continue;
994
995 // absorb all damage by default
996 uint32 currentAbsorb = damageInfo.GetDamage();
997
998 // This aura type is used both by Spirit of Redemption (death not really prevented, must grant all credit immediately) and Cheat Death (death prevented)
999 // repurpose PreventDefaultAction for this
1000 bool deathFullyPrevented = false;
1001
1002 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, currentAbsorb, deathFullyPrevented);
1003
1004 // absorb must be smaller than the damage itself
1005 currentAbsorb = std::min(currentAbsorb, damageInfo.GetDamage());
1006
1007 // if nothing is absorbed (for example because of a scripted cooldown) then skip this aura and proceed with dying
1008 if (!currentAbsorb)
1009 continue;
1010
1011 damageInfo.AbsorbDamage(currentAbsorb);
1012
1013 if (deathFullyPrevented)
1014 killed = false;
1015
1016 skipSettingDeathState = true;
1017
1018 if (currentAbsorb)
1019 {
1021 absorbLog.Attacker = attacker ? attacker->GetGUID() : ObjectGuid::Empty;
1022 absorbLog.Victim = victim->GetGUID();
1023 absorbLog.Caster = base->GetCasterGUID();
1024 absorbLog.AbsorbedSpellID = spellProto ? spellProto->Id : 0;
1025 absorbLog.AbsorbSpellID = base->GetId();
1026 absorbLog.Absorbed = currentAbsorb;
1027 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1028 absorbLog.LogData.Initialize(victim);
1029 victim->SendCombatLogMessage(&absorbLog);
1030 }
1031 }
1032
1033 damageTaken = damageInfo.GetDamage();
1034 }
1035 }
1036
1037 if (spellProto && spellProto->HasAttribute(SPELL_ATTR3_NO_DURABILITY_LOSS))
1038 durabilityLoss = false;
1039
1040 if (killed)
1041 Unit::Kill(attacker, victim, durabilityLoss, skipSettingDeathState);
1042 else
1043 {
1044 if (victim->GetTypeId() == TYPEID_PLAYER)
1046
1047 victim->ModifyHealth(-(int32)damageTaken);
1048
1049 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
1051
1052 if (victim->GetTypeId() != TYPEID_PLAYER)
1053 {
1054 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
1055 if (damagetype != DOT && damageTaken > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
1057
1058 if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT)))
1059 victim->GetThreatManager().AddThreat(attacker, float(damageTaken), spellProto);
1060 }
1061 else // victim is a player
1062 {
1063 // random durability for items (HIT TAKEN)
1064 if (durabilityLoss && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1065 {
1068 }
1069 }
1070
1071 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
1072 {
1073 // random durability for items (HIT DONE)
1074 if (durabilityLoss && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1075 {
1077 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
1078 }
1079 }
1080
1081 if (damagetype != NODAMAGE && damagetype != DOT)
1082 {
1083 if (victim != attacker && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR6_NO_PUSHBACK) || spellProto->HasAttribute(SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC))))
1084 {
1085 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
1086 {
1087 if (spell->getState() == SPELL_STATE_PREPARING)
1088 {
1089 auto isCastInterrupted = [&]()
1090 {
1091 if (!damageTaken)
1092 return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels);
1093
1094 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly))
1095 return true;
1096
1097 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels))
1098 return true;
1099
1100 return false;
1101 };
1102
1103 auto isCastDelayed = [&]()
1104 {
1105 if (!damageTaken)
1106 return false;
1107
1108 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly))
1109 return true;
1110
1111 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushback))
1112 return true;
1113
1114 return false;
1115 };
1116
1117 if (isCastInterrupted())
1118 victim->InterruptSpell(CURRENT_GENERIC_SPELL, false, false);
1119 else if (isCastDelayed())
1120 spell->Delayed();
1121 }
1122 }
1123
1124 if (damageTaken && victim->IsPlayer())
1125 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1126 if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration))
1127 spell->DelayedChannel();
1128 }
1129 }
1130
1131 // last damage from duel opponent
1132 if (duel_hasEnded)
1133 {
1134 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
1135
1136 ASSERT_NODEBUGINFO(he && he->duel);
1137
1138 if (duel_wasMounted) // In this case victim == mount
1139 victim->SetHealth(1);
1140 else
1141 he->SetHealth(1);
1142
1143 he->duel->Opponent->CombatStopWithPets(true);
1144 he->CombatStopWithPets(true);
1145
1146 he->CastSpell(he, 7267, true); // beg
1148 }
1149 }
1150
1151 // make player victims stand up automatically
1152 if (victim->GetStandState() && victim->IsPlayer())
1154
1155 return damageTaken;
1156}
1157
1158void Unit::CastStop(uint32 except_spellid)
1159{
1161 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1163}
1164
1165void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
1166{
1167 if (damage < 0)
1168 return;
1169
1170 Unit* victim = damageInfo->target;
1171 if (!victim || !victim->IsAlive())
1172 return;
1173
1174 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1175
1176 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
1178 {
1179 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1180 damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, victim, damage, spellInfo, attackType);
1181
1182 // Per-school calc
1183 switch (spellInfo->DmgClass)
1184 {
1185 // Melee and Ranged Spells
1188 {
1189 if (crit)
1190 {
1191 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1192
1193 // Calculate crit bonus
1194 uint32 crit_bonus = damage;
1195 // Apply crit_damage bonus for melee spells
1196 if (Player* modOwner = GetSpellModOwner())
1197 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritDamageAndHealing, crit_bonus);
1198 damage += crit_bonus;
1199
1200 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1201 float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1202
1203 if (critPctDamageMod != 0)
1204 AddPct(damage, critPctDamageMod);
1205 }
1206
1207 // Spell weapon based damage CAN BE crit & blocked at same time
1208 if (blocked)
1209 {
1210 // double blocked amount if block is critical
1211 uint32 value = victim->GetBlockPercent(GetLevel());
1212 if (victim->IsBlockCritical())
1213 {
1214 value *= 2; // double blocked percent
1216 }
1217
1218 damageInfo->blocked = CalculatePct(damage, value);
1219 if (damage <= int32(damageInfo->blocked))
1220 {
1221 damageInfo->blocked = uint32(damage);
1222 damageInfo->fullBlock = true;
1223 }
1224 damage -= damageInfo->blocked;
1225 }
1226
1227 if (CanApplyResilience())
1228 Unit::ApplyResilience(victim, &damage);
1229 break;
1230 }
1231 // Magical Attacks
1234 {
1235 // If crit add critical bonus
1236 if (crit)
1237 {
1238 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1239 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1240 }
1241
1242 if (CanApplyResilience())
1243 Unit::ApplyResilience(victim, &damage);
1244 break;
1245
1246 }
1247 default:
1248 break;
1249 }
1250 }
1251
1252 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1253 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage, spellInfo);
1254
1255 // Calculate absorb resist
1256 if (damage < 0)
1257 damage = 0;
1258
1259 damageInfo->damage = damage;
1260 damageInfo->originalDamage = damage;
1262 Unit::CalcAbsorbResist(dmgInfo, spell);
1263 damageInfo->absorb = dmgInfo.GetAbsorb();
1264 damageInfo->resist = dmgInfo.GetResist();
1265
1266 if (damageInfo->absorb)
1267 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1268
1269 if (damageInfo->resist)
1270 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1271
1272 damageInfo->damage = dmgInfo.GetDamage();
1273}
1274
1275void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1276{
1277 if (!damageInfo)
1278 return;
1279
1280 Unit* victim = damageInfo->target;
1281 if (!victim)
1282 return;
1283
1284 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1285 return;
1286
1287 if (!damageInfo->Spell)
1288 {
1289 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has no spell");
1290 return;
1291 }
1292
1293 // Call default DealDamage
1294 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1295 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), damageInfo->Spell, durabilityLoss);
1296}
1297
1299void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
1300{
1301 damageInfo->Attacker = this;
1302 damageInfo->Target = victim;
1303
1304 damageInfo->DamageSchoolMask = GetMeleeDamageSchoolMask(attackType);
1305 damageInfo->Damage = 0;
1306 damageInfo->OriginalDamage = 0;
1307 damageInfo->Absorb = 0;
1308 damageInfo->Resist = 0;
1309
1310 damageInfo->Blocked = 0;
1311 damageInfo->HitInfo = 0;
1312 damageInfo->TargetState = 0;
1313 damageInfo->RageGained = 0;
1314
1315 damageInfo->AttackType = attackType;
1316 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1317 damageInfo->ProcVictim = PROC_FLAG_NONE;
1318 damageInfo->CleanDamage = 0;
1319 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1320
1321 if (!victim)
1322 return;
1323
1324 if (!IsAlive() || !victim->IsAlive())
1325 return;
1326
1327 // Select HitInfo/procAttacker/procVictim flag based on attack type
1328 switch (attackType)
1329 {
1330 case BASE_ATTACK:
1333 break;
1334 case OFF_ATTACK:
1337 damageInfo->HitInfo = HITINFO_OFFHAND;
1338 break;
1339 default:
1340 return;
1341 }
1342
1343 // Physical Immune check
1344 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->DamageSchoolMask)))
1345 {
1346 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1347 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1348
1349 damageInfo->Damage = 0;
1350 damageInfo->CleanDamage = 0;
1351 return;
1352 }
1353
1354 uint32 damage = 0;
1355 damage += CalculateDamage(damageInfo->AttackType, false, true);
1356 // Add melee damage bonus
1357 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, nullptr, MECHANIC_NONE, SpellSchoolMask(damageInfo->DamageSchoolMask));
1358 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
1359
1360 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1361 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1362
1363 // Calculate armor reduction
1365 {
1366 damageInfo->Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1367 damageInfo->CleanDamage += damage - damageInfo->Damage;
1368 }
1369 else
1370 damageInfo->Damage = damage;
1371
1372 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1373
1374 switch (damageInfo->HitOutCome)
1375 {
1376 case MELEE_HIT_EVADE:
1378 damageInfo->TargetState = VICTIMSTATE_EVADES;
1379 damageInfo->OriginalDamage = damageInfo->Damage;
1380
1381 damageInfo->Damage = 0;
1382 damageInfo->CleanDamage = 0;
1383 return;
1384 case MELEE_HIT_MISS:
1385 damageInfo->HitInfo |= HITINFO_MISS;
1386 damageInfo->TargetState = VICTIMSTATE_INTACT;
1387 damageInfo->OriginalDamage = damageInfo->Damage;
1388
1389 damageInfo->Damage = 0;
1390 damageInfo->CleanDamage = 0;
1391 break;
1392 case MELEE_HIT_NORMAL:
1393 damageInfo->TargetState = VICTIMSTATE_HIT;
1394 damageInfo->OriginalDamage = damageInfo->Damage;
1395 break;
1396 case MELEE_HIT_CRIT:
1397 {
1398 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1399 damageInfo->TargetState = VICTIMSTATE_HIT;
1400
1401 // Crit bonus calc
1402 damageInfo->Damage *= 2;
1403
1404 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1406
1407 if (mod != 0)
1408 AddPct(damageInfo->Damage, mod);
1409
1410 damageInfo->OriginalDamage = damageInfo->Damage;
1411 break;
1412 }
1413 case MELEE_HIT_PARRY:
1414 damageInfo->TargetState = VICTIMSTATE_PARRY;
1415 damageInfo->CleanDamage += damageInfo->Damage;
1416
1417 damageInfo->OriginalDamage = damageInfo->Damage;
1418 damageInfo->Damage = 0;
1419 break;
1420 case MELEE_HIT_DODGE:
1421 damageInfo->TargetState = VICTIMSTATE_DODGE;
1422 damageInfo->CleanDamage += damageInfo->Damage;
1423
1424 damageInfo->OriginalDamage = damageInfo->Damage;
1425 damageInfo->Damage = 0;
1426 break;
1427 case MELEE_HIT_BLOCK:
1428 damageInfo->TargetState = VICTIMSTATE_HIT;
1429 damageInfo->HitInfo |= HITINFO_BLOCK;
1430 // 30% damage blocked, double blocked amount if block is critical
1431 damageInfo->Blocked = CalculatePct(damageInfo->Damage, damageInfo->Target->GetBlockPercent(GetLevel()));
1432 if (damageInfo->Target->IsBlockCritical())
1433 {
1434 damageInfo->Blocked *= 2;
1436 }
1437
1438 damageInfo->OriginalDamage = damageInfo->Damage;
1439 damageInfo->Damage -= damageInfo->Blocked;
1440 damageInfo->CleanDamage += damageInfo->Blocked;
1441 break;
1442 case MELEE_HIT_GLANCING:
1443 {
1444 damageInfo->HitInfo |= HITINFO_GLANCING;
1445 damageInfo->TargetState = VICTIMSTATE_HIT;
1446 int32 leveldif = int32(victim->GetLevel()) - int32(GetLevel());
1447 if (leveldif > 3)
1448 leveldif = 3;
1449
1450 damageInfo->OriginalDamage = damageInfo->Damage;
1451 float reducePercent = 1.f - leveldif * 0.1f;
1452 damageInfo->CleanDamage += damageInfo->Damage - uint32(reducePercent * damageInfo->Damage);
1453 damageInfo->Damage = uint32(reducePercent * damageInfo->Damage);
1454 break;
1455 }
1456 case MELEE_HIT_CRUSHING:
1457 damageInfo->HitInfo |= HITINFO_CRUSHING;
1458 damageInfo->TargetState = VICTIMSTATE_HIT;
1459 // 150% normal damage
1460 damageInfo->Damage += (damageInfo->Damage / 2);
1461 damageInfo->OriginalDamage = damageInfo->Damage;
1462 break;
1463 default:
1464 break;
1465 }
1466
1467 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1468 if (!(damageInfo->HitInfo & HITINFO_MISS))
1469 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1470
1471 int32 resilienceReduction = damageInfo->Damage;
1473 Unit::ApplyResilience(victim, &resilienceReduction);
1474 resilienceReduction = damageInfo->Damage - resilienceReduction;
1475 damageInfo->Damage -= resilienceReduction;
1476 damageInfo->CleanDamage += resilienceReduction;
1477 damageInfo->OriginalDamage -= resilienceReduction;
1478
1479 // Calculate absorb resist
1480 if (int32(damageInfo->Damage) > 0)
1481 {
1483 // Calculate absorb & resists
1484 DamageInfo dmgInfo(*damageInfo);
1485 Unit::CalcAbsorbResist(dmgInfo);
1486 damageInfo->Absorb = dmgInfo.GetAbsorb();
1487 damageInfo->Resist = dmgInfo.GetResist();
1488
1489 if (damageInfo->Absorb)
1490 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1491
1492 if (damageInfo->Resist)
1493 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1494
1495 damageInfo->Damage = dmgInfo.GetDamage();
1496 }
1497 else // Impossible get negative result but....
1498 damageInfo->Damage = 0;
1499}
1500
1501void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1502{
1503 Unit* victim = damageInfo->Target;
1504
1505 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1506 return;
1507
1508 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1510 {
1511 // Get attack timers
1512 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1513 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1514 // Reduce attack time
1515 if (victim->haveOffhandWeapon() && offtime < basetime)
1516 {
1517 float percent20 = victim->GetBaseAttackTime(OFF_ATTACK) * 0.20f;
1518 float percent60 = 3.0f * percent20;
1519 if (offtime > percent20 && offtime <= percent60)
1520 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1521 else if (offtime > percent60)
1522 {
1523 offtime -= 2.0f * percent20;
1524 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1525 }
1526 }
1527 else
1528 {
1529 float percent20 = victim->GetBaseAttackTime(BASE_ATTACK) * 0.20f;
1530 float percent60 = 3.0f * percent20;
1531 if (basetime > percent20 && basetime <= percent60)
1532 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1533 else if (basetime > percent60)
1534 {
1535 basetime -= 2.0f * percent20;
1536 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1537 }
1538 }
1539 }
1540
1541 // Call default DealDamage
1542 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1543 Unit::DealDamage(this, victim, damageInfo->Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->DamageSchoolMask), nullptr, durabilityLoss);
1544
1545 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1546 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1547 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1548 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1549 {
1550 // 20% base chance
1551 float chance = 20.0f;
1552
1553 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1554 if (victim->GetLevel() < 30)
1555 chance = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
1556
1557 uint32 const victimDefense = victim->GetMaxSkillValueForLevel(this);
1558 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1559
1560 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1561
1562 // -probability is between 0% and 40%
1563 RoundToInterval(chance, 0.0f, 40.0f);
1564 if (roll_chance_f(chance))
1565 CastSpell(victim, SPELL_DAZED, true);
1566 }
1567
1568 if (GetTypeId() == TYPEID_PLAYER)
1569 {
1570 DamageInfo dmgInfo(*damageInfo);
1571 ToPlayer()->CastItemCombatSpell(dmgInfo);
1572 }
1573
1574 // Do effect if any damage done to target
1575 if (damageInfo->Damage)
1576 {
1577 // We're going to call functions which can modify content of the list during iteration over it's elements
1578 // Let's copy the list so we can prevent iterator invalidation
1580 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1581 {
1582 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1583
1584 // Damage shield can be resisted...
1585 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
1586 if (missInfo != SPELL_MISS_NONE)
1587 {
1588 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1589 continue;
1590 }
1591
1592 // ...or immuned
1593 if (IsImmunedToDamage(this, spellInfo))
1594 {
1595 victim->SendSpellDamageImmune(this, spellInfo->Id, false);
1596 continue;
1597 }
1598
1599 uint32 damage = aurEff->GetAmount();
1600 if (Unit* caster = aurEff->GetCaster())
1601 {
1602 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo());
1603 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1604 }
1605
1606 DamageInfo damageInfo(this, victim, damage, spellInfo, spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
1607 victim->CalcAbsorbResist(damageInfo);
1608 damage = damageInfo.GetDamage();
1609 Unit::DealDamageMods(victim, this, damage, nullptr);
1610
1612 damageShield.Attacker = victim->GetGUID();
1613 damageShield.Defender = GetGUID();
1614 damageShield.SpellID = spellInfo->Id;
1615 damageShield.TotalDamage = damage;
1616 damageShield.OriginalDamage = damageInfo.GetOriginalDamage();
1617 damageShield.OverKill = std::max(int32(damage) - int32(GetHealth()), 0);
1618 damageShield.SchoolMask = spellInfo->SchoolMask;
1619 damageShield.LogAbsorbed = damageInfo.GetAbsorb();
1620
1621 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1622
1623 damageShield.LogData.Initialize(this);
1624 victim->SendCombatLogMessage(&damageShield);
1625 }
1626 }
1627}
1628
1629void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinity::IteratorPair<int32 const*> spellVisualKitIds /*= {}*/, int32 sequenceVariation /*= 0*/)
1630{
1632 packet.Guid = GetGUID();
1633 packet.EmoteID = emoteId;
1634
1635 if (EmotesEntry const* emotesEntry = sEmotesStore.LookupEntry(emoteId))
1636 if (emotesEntry->AnimID == ANIM_MOUNT_SPECIAL || emotesEntry->AnimID == ANIM_MOUNT_SELF_SPECIAL)
1637 std::copy(spellVisualKitIds.begin(), spellVisualKitIds.end(), std::back_inserter(packet.SpellVisualKitIDs));
1638
1639 packet.SequenceVariation = sequenceVariation;
1640
1641 if (target)
1642 target->SendDirectMessage(packet.Write());
1643 else
1644 SendMessageToSet(packet.Write(), true);
1645}
1646
1647/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1648{
1649 // only physical spells damage gets reduced by armor
1650 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1651 return false;
1652
1653 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1654}
1655
1656/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1657{
1658 float armor = float(victim->GetArmor());
1659
1660 if (attacker)
1661 {
1662 armor *= victim->GetArmorMultiplierForTarget(attacker);
1663
1664 // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
1665 int32 armorBypassPct = 0;
1667 for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i)
1668 if ((*i)->GetCasterGUID() == attacker->GetGUID())
1669 armorBypassPct += (*i)->GetAmount();
1670 armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100));
1671
1672 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1674
1675 if (spellInfo)
1676 if (Player* modOwner = attacker->GetSpellModOwner())
1677 modOwner->ApplySpellMod(spellInfo, SpellModOp::TargetResistance, armor);
1678
1680 for (AuraEffect const* aurEff : resIgnoreAuras)
1681 {
1682 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1683 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1684 }
1685
1686 // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
1687 if (attacker->GetTypeId() == TYPEID_PLAYER)
1688 {
1689 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1690
1691 Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
1692 arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
1693 {
1694 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
1695 });
1696
1697 // no more than 100%
1698 RoundToInterval(arpPct, 0.f, 100.f);
1699
1700 float maxArmorPen = 0.f;
1701 if (victim->GetLevelForTarget(attacker) < 60)
1702 maxArmorPen = float(400 + 85 * victim->GetLevelForTarget(attacker));
1703 else
1704 maxArmorPen = 400 + 85 * victim->GetLevelForTarget(attacker) + 4.5f * 85 * (victim->GetLevelForTarget(attacker) - 59);
1705
1706 // Cap armor penetration to this number
1707 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1708 // Figure out how much armor do we ignore
1709 armor -= CalculatePct(maxArmorPen, arpPct);
1710 }
1711 }
1712
1713 if (G3D::fuzzyLe(armor, 0.0f))
1714 return damage;
1715
1716 Classes attackerClass = CLASS_WARRIOR;
1717 if (attacker)
1718 {
1719 attackerLevel = attacker->GetLevelForTarget(victim);
1720 attackerClass = Classes(attacker->GetClass());
1721 }
1722
1723 // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
1724 float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, attackerClass, 0);
1725
1726 if (!(armor + armorConstant))
1727 return damage;
1728
1729 float mitigation = std::min(armor / (armor + armorConstant), 0.85f);
1730 return uint32(std::max(damage * (1.0f - mitigation), 0.0f));
1731}
1732
1733/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1734{
1735 // Magic damage, check for resists
1736 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1737 return 0;
1738
1739 // Npcs can have holy resistance
1740 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1741 return 0;
1742
1743 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1744 float discreteResistProbability[11] = { };
1745 if (averageResist <= 0.1f)
1746 {
1747 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1748 discreteResistProbability[1] = 5.0f * averageResist;
1749 discreteResistProbability[2] = 2.5f * averageResist;
1750 }
1751 else
1752 {
1753 for (uint32 i = 0; i < 11; ++i)
1754 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1755 }
1756
1757 float roll = rand_norm();
1758 float probabilitySum = 0.0f;
1759
1760 uint32 resistance = 0;
1761 for (; resistance < 11; ++resistance)
1762 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1763 break;
1764
1765 float damageResisted = damage * resistance / 10.f;
1766 if (damageResisted > 0.0f) // if any damage was resisted
1767 {
1768 int32 ignoredResistance = 0;
1769
1770 if (attacker)
1771 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1772
1773 ignoredResistance = std::min<int32>(ignoredResistance, 100);
1774 ApplyPct(damageResisted, 100 - ignoredResistance);
1775
1776 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1777 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1778 {
1779 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1780 float armorReduction = damage - damageAfterArmor;
1781
1782 // pick the lower one, the weakest resistance counts
1783 damageResisted = std::min(damageResisted, armorReduction);
1784 }
1785 }
1786
1787 damageResisted = std::max(damageResisted, 0.f);
1788 return uint32(damageResisted);
1789}
1790
1791/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo /*= nullptr*/)
1792{
1793 float victimResistance = float(victim->GetResistance(schoolMask));
1794 if (caster)
1795 {
1796 // pets inherit 100% of masters penetration
1797 if (Player const* player = caster->GetSpellModOwner())
1798 {
1799 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1800 victimResistance -= float(player->GetSpellPenetrationItemMod());
1801 }
1802 else if (Unit const* unitCaster = caster->ToUnit())
1803 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1804 }
1805
1806 // holy resistance exists in pve and comes from level difference, ignore template values
1807 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1808 victimResistance = 0.0f;
1809
1810 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1811 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->Id == 116858)
1812 victimResistance = 0.0f;
1813
1814 victimResistance = std::max(victimResistance, 0.0f);
1815
1816 // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
1817 // gameobject caster -- should it have level based resistance?
1818 if (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
1819 victimResistance += std::max((float(victim->GetLevelForTarget(caster)) - float(caster->GetLevelForTarget(victim))) * 5.0f, 0.0f);
1820
1821 static uint32 const bossLevel = 83;
1822 static float const bossResistanceConstant = 510.0f;
1823 uint32 level = caster ? victim->GetLevelForTarget(caster) : victim->GetLevel();
1824 float resistanceConstant = 0.0f;
1825
1826 if (level == bossLevel)
1827 resistanceConstant = bossResistanceConstant;
1828 else
1829 resistanceConstant = level * 5.0f;
1830
1831 return victimResistance / (victimResistance + resistanceConstant);
1832}
1833
1834/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1835{
1836 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1837 return;
1838
1839 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1840
1841 // Ignore Absorption Auras
1842 float auraAbsorbMod = 0.f;
1843 if (Unit* attacker = damageInfo.GetAttacker())
1845
1846 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1847
1848 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1849
1850 if (spell)
1851 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1852
1853 damageInfo.ResistDamage(resistedDamage);
1854
1855 // We're going to call functions which can modify content of the list during iteration over it's elements
1856 // Let's copy the list so we can prevent iterator invalidation
1858 std::sort(vSchoolAbsorbCopy.begin(), vSchoolAbsorbCopy.end(), Trinity::AbsorbAuraOrderPred());
1859
1860 // absorb without mana cost
1861 for (auto itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1862 {
1863 AuraEffect* absorbAurEff = *itr;
1864 // Check if aura was removed during iteration - we don't need to work on such auras
1865 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1866 if (!aurApp)
1867 continue;
1868 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1869 continue;
1870
1871 // get amount which can be still absorbed by the aura
1872 int32 currentAbsorb = absorbAurEff->GetAmount();
1873 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1874 if (currentAbsorb < 0)
1875 currentAbsorb = 0;
1876
1878 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1879
1880 uint32 tempAbsorb = uint32(currentAbsorb);
1881
1882 bool defaultPrevented = false;
1883
1884 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1885 currentAbsorb = tempAbsorb;
1886
1887 if (!defaultPrevented)
1888 {
1889 // absorb must be smaller than the damage itself
1890 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1891
1892 damageInfo.AbsorbDamage(currentAbsorb);
1893
1894 tempAbsorb = currentAbsorb;
1895 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1896
1897 // Check if our aura is using amount to count damage
1898 if (absorbAurEff->GetAmount() >= 0)
1899 {
1900 // Reduce shield amount
1901 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1902 // Aura cannot absorb anything more - remove it
1903 if (absorbAurEff->GetAmount() <= 0)
1904 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1905 }
1906 }
1907
1909 damageInfo.ModifyDamage(absorbIgnoringDamage);
1910
1911 if (currentAbsorb)
1912 {
1914 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1915 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1916 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1917 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1918 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1919 absorbLog.Absorbed = currentAbsorb;
1920 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1921 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1922 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
1923 }
1924 }
1925
1926 // absorb by mana cost
1928 for (auto itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1929 {
1930 AuraEffect* absorbAurEff = *itr;
1931 // Check if aura was removed during iteration - we don't need to work on such auras
1932 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1933 if (!aurApp)
1934 continue;
1935 // check damage school mask
1936 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1937 continue;
1938
1939 // get amount which can be still absorbed by the aura
1940 int32 currentAbsorb = absorbAurEff->GetAmount();
1941 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1942 if (currentAbsorb < 0)
1943 currentAbsorb = 0;
1944
1946 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1947
1948 uint32 tempAbsorb = currentAbsorb;
1949
1950 bool defaultPrevented = false;
1951
1952 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1953 currentAbsorb = tempAbsorb;
1954
1955 if (!defaultPrevented)
1956 {
1957 // absorb must be smaller than the damage itself
1958 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1959
1960 int32 manaReduction = currentAbsorb;
1961
1962 // lower absorb amount by talents
1963 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
1964 manaReduction = int32(float(manaReduction) * manaMultiplier);
1965
1966 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
1967
1968 // take case when mana has ended up into account
1969 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
1970
1971 damageInfo.AbsorbDamage(currentAbsorb);
1972
1973 tempAbsorb = currentAbsorb;
1974 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1975
1976 // Check if our aura is using amount to count damage
1977 if (absorbAurEff->GetAmount() >= 0)
1978 {
1979 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1980 if ((absorbAurEff->GetAmount() <= 0))
1981 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1982 }
1983 }
1984
1986 damageInfo.ModifyDamage(absorbIgnoringDamage);
1987
1988 if (currentAbsorb)
1989 {
1991 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1992 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1993 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1994 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1995 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1996 absorbLog.Absorbed = currentAbsorb;
1997 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1998 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1999 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
2000 }
2001 }
2002
2003 // split damage auras - only when not damaging self
2004 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
2005 {
2006 // We're going to call functions which can modify content of the list during iteration over it's elements
2007 // Let's copy the list so we can prevent iterator invalidation
2009 for (auto itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
2010 {
2011 // Check if aura was removed during iteration - we don't need to work on such auras
2012 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
2013 if (!aurApp)
2014 continue;
2015
2016 // check damage school mask
2017 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
2018 continue;
2019
2020 // Damage can be splitted only if aura has an alive caster
2021 Unit* caster = (*itr)->GetCaster();
2022 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
2023 continue;
2024
2025 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
2026
2027 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
2028
2029 // absorb must be smaller than the damage itself
2030 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
2031
2032 damageInfo.AbsorbDamage(splitDamage);
2033
2034 // check if caster is immune to damage
2035 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
2036 {
2037 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
2038 continue;
2039 }
2040
2041 uint32 split_absorb = 0;
2042 Unit::DealDamageMods(damageInfo.GetAttacker(), caster, splitDamage, &split_absorb);
2043
2044 // sparring
2045 if (Creature* victimCreature = damageInfo.GetVictim()->ToCreature())
2046 {
2047 if (victimCreature->ShouldFakeDamageFrom(damageInfo.GetAttacker()))
2048 damageInfo.ModifyDamage(damageInfo.GetDamage() * -1);
2049 }
2050
2051 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetSpellInfo(), (*itr)->GetBase()->GetSpellVisual(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastId());
2052 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2053 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2054 log.damage = splitDamage;
2055 log.originalDamage = splitDamage;
2056 log.absorb = split_absorb;
2057 caster->SendSpellNonMeleeDamageLog(&log);
2058
2059 // break 'Fear' and similar auras
2061 }
2062 }
2063}
2064
2065/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2066{
2067 if (!healInfo.GetHeal())
2068 return;
2069
2071 for (auto i = vHealAbsorb.begin(); i != vHealAbsorb.end() && healInfo.GetHeal() > 0; ++i)
2072 {
2073 AuraEffect* absorbAurEff = *i;
2074 // Check if aura was removed during iteration - we don't need to work on such auras
2075 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(healInfo.GetTarget()->GetGUID());
2076 if (!aurApp)
2077 continue;
2078 if (!(absorbAurEff->GetMiscValue() & healInfo.GetSchoolMask()))
2079 continue;
2080
2081 // get amount which can be still absorbed by the aura
2082 int32 currentAbsorb = absorbAurEff->GetAmount();
2083 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
2084 if (currentAbsorb < 0)
2085 currentAbsorb = 0;
2086
2087 uint32 tempAbsorb = uint32(currentAbsorb);
2088
2089 bool defaultPrevented = false;
2090
2091 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb, defaultPrevented);
2092 currentAbsorb = tempAbsorb;
2093
2094 if (!defaultPrevented)
2095 {
2096 // absorb must be smaller than the heal itself
2097 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(healInfo.GetHeal()));
2098
2099 healInfo.AbsorbHeal(currentAbsorb);
2100
2101 tempAbsorb = currentAbsorb;
2102 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb);
2103
2104 // Check if our aura is using amount to count heal
2105 if (absorbAurEff->GetAmount() >= 0)
2106 {
2107 // Reduce shield amount
2108 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2109 // Aura cannot absorb anything more - remove it
2110 if (absorbAurEff->GetAmount() <= 0)
2111 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2112 }
2113 }
2114
2115 if (currentAbsorb)
2116 {
2118 absorbLog.Healer = healInfo.GetHealer() ? healInfo.GetHealer()->GetGUID() : ObjectGuid::Empty;
2119 absorbLog.Target = healInfo.GetTarget()->GetGUID();
2120 absorbLog.AbsorbCaster = absorbAurEff->GetBase()->GetCasterGUID();
2121 absorbLog.AbsorbedSpellID = healInfo.GetSpellInfo() ? healInfo.GetSpellInfo()->Id : 0;
2122 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2123 absorbLog.Absorbed = currentAbsorb;
2124 absorbLog.OriginalHeal = healInfo.GetOriginalHeal();
2125 healInfo.GetTarget()->SendMessageToSet(absorbLog.Write(), true);
2126 }
2127 }
2128}
2129
2131{
2133 return;
2134
2136 return;
2137
2138 if (IsCreature() && !ToCreature()->CanMelee())
2139 return;
2140
2142 {
2144 if (!channeledSpell || !channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL))
2145 return;
2146 }
2147
2148 Unit* victim = GetVictim();
2149 if (!victim)
2150 return;
2151
2152 auto getAutoAttackError = [&]() -> Optional<AttackSwingErr>
2153 {
2154 if (!IsWithinMeleeRange(victim))
2156
2157 //120 degrees of radiant range, if player is not in boundary radius
2158 if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
2160
2161 return {};
2162 };
2163
2165 {
2166 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2167 if (!autoAttackError)
2168 {
2169 // prevent base and off attack in same time, delay attack at 0.2 sec
2170 if (haveOffhandWeapon())
2173
2174 // do attack
2177 }
2178 else
2180
2181 if (Player* attackerPlayer = ToPlayer())
2182 attackerPlayer->SetAttackSwingError(autoAttackError);
2183 }
2184
2186 {
2187 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2188 if (!autoAttackError)
2189 {
2190 // prevent base and off attack in same time, delay attack at 0.2 sec
2193
2194 // do attack
2197 }
2198 else
2200 }
2201}
2202
2203// Calculates the normalized rage amount per weapon swing
2204static uint32 CalcMeleeAttackRageGain(Unit const* attacker, WeaponAttackType attType)
2205{
2206 if (!attacker || (attType != BASE_ATTACK && attType != OFF_ATTACK))
2207 return 0;
2208
2209 uint32 rage = uint32(attacker->GetBaseAttackTime(attType) / 1000.f * 1.75f);
2210 if (attType == OFF_ATTACK)
2211 rage /= 2;
2212
2213 return rage;
2214}
2215
2216void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2217{
2219 return;
2220
2222 return;
2223
2225 return;
2226
2227 if (!victim->IsAlive())
2228 return;
2229
2230 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2231 return;
2232
2233 AtTargetAttacked(victim, true);
2235
2236 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2237 return; // ignore ranged case
2238
2239 if (!extra && _lastExtraAttackSpell)
2241
2242 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2243 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2245 else
2246 {
2247 // attack can be redirected to another target
2248 victim = GetMeleeHitRedirectTarget(victim);
2249
2251 uint32 meleeAttackSpellId = 0;
2252 if (attType == BASE_ATTACK)
2253 {
2254 if (!meleeAttackOverrides.empty())
2255 meleeAttackSpellId = meleeAttackOverrides.front()->GetSpellEffectInfo().TriggerSpell;
2256 }
2257 else
2258 {
2259 auto itr = std::find_if(meleeAttackOverrides.begin(), meleeAttackOverrides.end(), [&](AuraEffect const* aurEff)
2260 {
2261 return aurEff->GetSpellEffectInfo().MiscValue != 0;
2262 });
2263 if (itr != meleeAttackOverrides.end())
2264 meleeAttackSpellId = (*itr)->GetSpellEffectInfo().MiscValue;
2265 }
2266
2267 if (!meleeAttackSpellId)
2268 {
2269 CalcDamageInfo damageInfo;
2270 CalculateMeleeDamage(victim, &damageInfo, attType);
2271 // Send log damage message to client
2272 Unit::DealDamageMods(damageInfo.Attacker, victim, damageInfo.Damage, &damageInfo.Absorb);
2273
2274 // sparring
2275 if (Creature* victimCreature = victim->ToCreature())
2276 {
2277 if (victimCreature->ShouldFakeDamageFrom(damageInfo.Attacker))
2278 damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
2279 }
2280
2281 // Rage reward
2282 if (this != victim && damageInfo.HitOutCome != MELEE_HIT_MISS && GetPowerType() == POWER_RAGE)
2283 {
2284 if (uint32 rageReward = CalcMeleeAttackRageGain(this, attType))
2285 {
2286 damageInfo.HitInfo |= HITINFO_RAGE_GAIN;
2287 damageInfo.RageGained = RewardRage(rageReward);
2288 }
2289 }
2290
2291 SendAttackStateUpdate(&damageInfo);
2292
2293 _lastDamagedTargetGuid = victim->GetGUID();
2294
2295 DealMeleeDamage(&damageInfo, true);
2296
2297 DamageInfo dmgInfo(damageInfo);
2298 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2299
2300 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2301 GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.Damage, damageInfo.Absorb, damageInfo.Blocked, damageInfo.Resist);
2302 }
2303 else
2304 {
2305 CastSpell(victim, meleeAttackSpellId, true);
2306
2308 if (attType == OFF_ATTACK)
2309 hitInfo |= HITINFO_OFFHAND;
2310
2311 SendAttackStateUpdate(hitInfo, victim, 0, GetMeleeDamageSchoolMask(), 0, 0, 0, VICTIMSTATE_HIT, 0, 0);
2312 }
2313 }
2314}
2315
2317{
2318 while (count)
2319 {
2320 --count;
2321 AttackerStateUpdate(victim, BASE_ATTACK, true);
2322 }
2323}
2324
2326{
2328 if (!targetGUID)
2329 {
2330 ObjectGuid selection = GetTarget();
2331 if (!selection.IsEmpty())
2332 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2333 else
2334 return;
2335 }
2336
2337 extraAttacksTargets[targetGUID] += count;
2338}
2339
2341{
2342 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
2343 return MELEE_HIT_EVADE;
2344
2345 // Miss chance based on melee
2346 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, nullptr) * 100.0f);
2347
2348 // Critical hit chance
2350
2351 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2352 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2353 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2354
2355 // melee attack table implementation
2356 // outcome priority:
2357 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2358 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2359
2360 int32 sum = 0, tmp = 0;
2361 int32 roll = urand(0, 9999);
2362
2363 int32 attackerLevel = GetLevelForTarget(victim);
2364 int32 victimLevel = victim->GetLevelForTarget(this);
2365
2366 // check if attack comes from behind, nobody can parry or block if attacker is behind
2367 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2368
2369 // only creatures can dodge if attacker is behind
2370 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2371
2372 // if victim is casting or cc'd it can't avoid attacks
2373 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2374 {
2375 canDodge = false;
2376 canParryOrBlock = false;
2377 }
2378
2379 // 1. MISS
2380 tmp = miss_chance;
2381 if (tmp > 0 && roll < (sum += tmp))
2382 return MELEE_HIT_MISS;
2383
2384 // always crit against a sitting target (except 0 crit chance)
2385 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2386 return MELEE_HIT_CRIT;
2387
2388 // 2. DODGE
2389 if (canDodge)
2390 {
2391 tmp = dodge_chance;
2392 if (tmp > 0 // check if unit _can_ dodge
2393 && roll < (sum += tmp))
2394 return MELEE_HIT_DODGE;
2395 }
2396
2397 // 3. PARRY
2398 if (canParryOrBlock)
2399 {
2400 tmp = parry_chance;
2401 if (tmp > 0 // check if unit _can_ parry
2402 && roll < (sum += tmp))
2403 return MELEE_HIT_PARRY;
2404 }
2405
2406 // 4. GLANCING
2407 // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
2408 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2409 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2410 attackerLevel + 3 < victimLevel)
2411 {
2412 // cap possible value (with bonuses > max skill)
2413 tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100;
2414 if (tmp > 0 && roll < (sum += tmp))
2415 return MELEE_HIT_GLANCING;
2416 }
2417
2418 // 5. BLOCK
2419 if (canParryOrBlock)
2420 {
2421 tmp = block_chance;
2422 if (tmp > 0 // check if unit _can_ block
2423 && roll < (sum += tmp))
2424 return MELEE_HIT_BLOCK;
2425 }
2426
2427 // 6.CRIT
2428 tmp = crit_chance;
2429 if (tmp > 0 && roll < (sum += tmp))
2430 return MELEE_HIT_CRIT;
2431
2432 // 7. CRUSHING
2433 // mobs can score crushing blows if they're 4 or more levels above victim
2434 if (attackerLevel >= victimLevel + 4 &&
2435 // can be from by creature (if can) or from controlled player that considered as creature
2438 {
2439 // add 2% chance per level, min. is 15%
2440 tmp = attackerLevel - victimLevel * 1000 - 1500;
2441 if (roll < (sum += tmp))
2442 {
2443 TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <{}, {})", sum-tmp, sum);
2444 return MELEE_HIT_CRUSHING;
2445 }
2446 }
2447
2448 // 8. HIT
2449 return MELEE_HIT_NORMAL;
2450}
2451
2452uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
2453{
2454 float minDamage = 0.0f;
2455 float maxDamage = 0.0f;
2456
2457 if (normalized || !addTotalPct)
2458 {
2459 CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
2460 if (IsInFeralForm() && attType == BASE_ATTACK)
2461 {
2462 float minOffhandDamage = 0.0f;
2463 float maxOffhandDamage = 0.0f;
2464 CalculateMinMaxDamage(OFF_ATTACK, normalized, addTotalPct, minOffhandDamage, maxOffhandDamage);
2465 minDamage += minOffhandDamage;
2466 maxDamage += maxOffhandDamage;
2467 }
2468 }
2469 else
2470 {
2471 switch (attType)
2472 {
2473 case RANGED_ATTACK:
2474 minDamage = m_unitData->MinRangedDamage;
2475 maxDamage = m_unitData->MaxRangedDamage;
2476 break;
2477 case BASE_ATTACK:
2478 minDamage = m_unitData->MinDamage;
2479 maxDamage = m_unitData->MaxDamage;
2480 if (IsInFeralForm())
2481 {
2482 minDamage += m_unitData->MinOffHandDamage;
2483 maxDamage += m_unitData->MaxOffHandDamage;
2484 }
2485 break;
2486 case OFF_ATTACK:
2487 minDamage = m_unitData->MinOffHandDamage;
2488 maxDamage = m_unitData->MaxOffHandDamage;
2489 break;
2490 default:
2491 break;
2492 }
2493 }
2494
2495 minDamage = std::max(0.f, minDamage);
2496 maxDamage = std::max(0.f, maxDamage);
2497
2498 if (minDamage > maxDamage)
2499 std::swap(minDamage, maxDamage);
2500
2501 return urand(uint32(minDamage), uint32(maxDamage));
2502}
2503
2505{
2507 packet.Attacker = GetGUID();
2508 packet.Victim = victim->GetGUID();
2509 SendMessageToSet(packet.Write(), true);
2510}
2511
2513{
2514 SendMessageToSet(WorldPackets::Combat::SAttackStop(this, victim).Write(), true);
2515
2516 if (victim)
2517 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2518 else
2519 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2520}
2521
2523{
2525 return true;
2526 return false;
2527}
2528
2530{
2531 if (!spellInfo)
2532 return 0;
2533
2534 int32 resistMech = 0;
2535 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2536 {
2537 if (!effect.IsEffect())
2538 break;
2539
2540 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2541 if (effectMech)
2542 {
2544 if (resistMech < temp)
2545 resistMech = temp;
2546 }
2547 }
2548
2549 return std::max(resistMech, 0);
2550}
2551
2552bool Unit::CanUseAttackType(uint8 attacktype) const
2553{
2554 switch (attacktype)
2555 {
2556 case BASE_ATTACK:
2558 case OFF_ATTACK:
2560 case RANGED_ATTACK:
2562 default:
2563 return true;
2564 }
2565}
2566
2567// Melee based spells hit result calculations
2569{
2570 if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE))
2571 return SPELL_MISS_NONE;
2572
2573 WeaponAttackType attType = BASE_ATTACK;
2574
2575 // Check damage class instead of attack type to correctly handle judgements
2576 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2577 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2578 attType = RANGED_ATTACK;
2579
2580 uint32 roll = urand(0, 9999);
2581
2582 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo) * 100.0f);
2583
2584 // Roll miss
2585 uint32 tmp = missChance;
2586 if (roll < tmp)
2587 return SPELL_MISS_MISS;
2588
2589 // Chance resist mechanic
2590 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2591 tmp += resist_chance;
2592 if (roll < tmp)
2593 return SPELL_MISS_RESIST;
2594
2595 // Same spells cannot be parried/dodged
2597 return SPELL_MISS_NONE;
2598
2599 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
2600 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
2601 bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
2602
2603 // if victim is casting or cc'd it can't avoid attacks
2604 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2605 {
2606 canDodge = false;
2607 canParry = false;
2608 canBlock = false;
2609 }
2610
2611 // Ranged attacks can only miss, resist and deflect and get blocked
2612 if (attType == RANGED_ATTACK)
2613 {
2614 canParry = false;
2615 canDodge = false;
2616
2617 // only if in front
2618 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2619 {
2620 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
2621 tmp += deflect_chance;
2622 if (roll < tmp)
2623 return SPELL_MISS_DEFLECT;
2624 }
2625 }
2626
2627 // Check for attack from behind
2628 if (!victim->HasInArc(float(M_PI), this))
2629 {
2631 {
2632 // Can't dodge from behind in PvP (but its possible in PvE)
2633 if (victim->GetTypeId() == TYPEID_PLAYER)
2634 canDodge = false;
2635 // Can't parry or block
2636 canParry = false;
2637 canBlock = false;
2638 }
2639 else // Only deterrence as of 3.3.5
2640 {
2642 canParry = false;
2643 }
2644 }
2645
2646 // Ignore combat result aura
2648 for (AuraEffect const* aurEff : ignore)
2649 {
2650 if (!aurEff->IsAffectingSpell(spellInfo))
2651 continue;
2652
2653 switch (aurEff->GetMiscValue())
2654 {
2655 case MELEE_HIT_DODGE:
2656 canDodge = false;
2657 break;
2658 case MELEE_HIT_BLOCK:
2659 canBlock = false;
2660 break;
2661 case MELEE_HIT_PARRY:
2662 canParry = false;
2663 break;
2664 default:
2665 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2666 break;
2667 }
2668 }
2669
2670 if (canDodge)
2671 {
2672 // Roll dodge
2673 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2674 if (dodgeChance < 0)
2675 dodgeChance = 0;
2676
2677 if (roll < (tmp += dodgeChance))
2678 return SPELL_MISS_DODGE;
2679 }
2680
2681 if (canParry)
2682 {
2683 // Roll parry
2684 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2685 if (parryChance < 0)
2686 parryChance = 0;
2687
2688 tmp += parryChance;
2689 if (roll < tmp)
2690 return SPELL_MISS_PARRY;
2691 }
2692
2693 if (canBlock)
2694 {
2695 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2696 if (blockChance < 0)
2697 blockChance = 0;
2698 tmp += blockChance;
2699
2700 if (roll < tmp)
2701 return SPELL_MISS_BLOCK;
2702 }
2703
2704 return SPELL_MISS_NONE;
2705}
2706
2707float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2708{
2709 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2710
2711 float chance = 0.0f;
2712 float levelBonus = 0.0f;
2713 if (Player const* playerVictim = victim->ToPlayer())
2714 chance = playerVictim->m_activePlayerData->DodgePercentage;
2715 else
2716 {
2717 if (!victim->IsTotem())
2718 {
2719 chance = 3.0f;
2721
2722 if (levelDiff > 0)
2723 levelBonus = 1.5f * levelDiff;
2724 }
2725 }
2726
2727 chance += levelBonus;
2728
2729 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2731
2732 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2734
2735 // Reduce dodge chance by attacker expertise rating
2736 if (GetTypeId() == TYPEID_PLAYER)
2737 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2738 else
2740 return std::max(chance, 0.0f);
2741}
2742
2743float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2744{
2745 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2746
2747 float chance = 0.0f;
2748 float levelBonus = 0.0f;
2749 if (Player const* playerVictim = victim->ToPlayer())
2750 {
2751 if (playerVictim->CanParry())
2752 {
2753 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2754 if (!tmpitem)
2755 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2756
2757 if (tmpitem)
2758 chance = playerVictim->m_activePlayerData->ParryPercentage;
2759 }
2760 }
2761 else
2762 {
2764 {
2765 chance = 6.0f;
2767
2768 if (levelDiff > 0)
2769 levelBonus = 1.5f * levelDiff;
2770 }
2771 }
2772
2773 chance += levelBonus;
2774
2775 // Reduce parry chance by attacker expertise rating
2776 if (GetTypeId() == TYPEID_PLAYER)
2777 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2778 else
2780 return std::max(chance, 0.0f);
2781}
2782
2784{
2785 float miss_chance = 5.0f;
2786
2787 return miss_chance;
2788}
2789
2790float Unit::GetUnitBlockChance(WeaponAttackType /*attType*/, Unit const* victim) const
2791{
2792 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2793
2794 float chance = 0.0f;
2795 float levelBonus = 0.0f;
2796 if (Player const* playerVictim = victim->ToPlayer())
2797 {
2798 if (playerVictim->CanBlock())
2799 {
2800 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2801 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD)
2802 chance = playerVictim->m_activePlayerData->BlockPercentage;
2803 }
2804 }
2805 else
2806 {
2808 {
2809 chance = 3.0f;
2811
2812 if (levelDiff > 0)
2813 levelBonus = 1.5f * levelDiff;
2814 }
2815 }
2816
2817 chance += levelBonus;
2818 return std::max(chance, 0.0f);
2819}
2820
2822{
2823 float chance = 0.0f;
2824 if (Player const* thisPlayer = ToPlayer())
2825 {
2826 switch (attackType)
2827 {
2828 case BASE_ATTACK:
2829 chance = thisPlayer->m_activePlayerData->CritPercentage;
2830 break;
2831 case OFF_ATTACK:
2832 chance = thisPlayer->m_activePlayerData->OffhandCritPercentage;
2833 break;
2834 case RANGED_ATTACK:
2835 chance = thisPlayer->m_activePlayerData->RangedCritPercentage;
2836 break;
2837 // Just for good manner
2838 default:
2839 chance = 0.0f;
2840 break;
2841 }
2842 }
2843 else
2844 {
2845 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2846 {
2847 chance = 5.0f;
2850 }
2851 }
2852
2853 return chance;
2854}
2855
2856float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2857{
2858 float chance = critDone;
2859
2860 // flat aura mods
2861 if (attackType != RANGED_ATTACK)
2863
2865 {
2866 return !HealthBelowPct(aurEff->GetMiscValueB());
2867 });
2868
2869 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool
2870 {
2871 return aurEff->GetCasterGUID() == attacker->GetGUID();
2872 });
2873
2874 if (TempSummon const* tempSummon = attacker->ToTempSummon())
2875 {
2876 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
2877 {
2878 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
2879 });
2880 }
2881
2883
2884 return std::max(chance, 0.0f);
2885}
2886
2887float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2888{
2889 float chance = GetUnitCriticalChanceDone(attackType);
2890 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2891}
2892
2894{
2895 while (!m_removedAuras.empty())
2896 {
2897 delete m_removedAuras.front();
2898 m_removedAuras.pop_front();
2899 }
2900
2902}
2903
2905{
2906 if (!_spellHistory->IsPaused())
2907 _spellHistory->Update();
2908
2911
2912 // remove finished spells from current pointers
2913 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
2914 {
2915 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2916 {
2917 m_currentSpells[i]->SetReferencedFromCurrent(false);
2918 m_currentSpells[i] = nullptr; // remove pointer
2919 }
2920 }
2921
2922 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2924 {
2925 Aura* i_aura = m_auraUpdateIterator->second;
2926 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2927 i_aura->UpdateOwner(time, this);
2928 }
2929
2930 // remove expired auras - do that after updates(used in scripts?)
2931 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2932 {
2933 if (i->second->IsExpired())
2935 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2936 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2937 else
2938 ++i;
2939 }
2940
2941 for (AuraApplication* visibleAura : m_visibleAurasToUpdate)
2942 visibleAura->ClientUpdate();
2943
2944 m_visibleAurasToUpdate.clear();
2945
2947
2948 if (!m_gameObj.empty())
2949 {
2950 GameObjectList::iterator itr;
2951 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
2952 {
2953 if (!(*itr)->isSpawned())
2954 {
2955 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
2956 (*itr)->SetRespawnTime(0);
2957 (*itr)->Delete();
2958 m_gameObj.erase(itr++);
2959 }
2960 else
2961 ++itr;
2962 }
2963 }
2964}
2965
2967{
2968 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
2969
2970 // check "realtime" interrupts
2971 // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
2972 if ((isMoving() && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckMovement() != SPELL_CAST_OK) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->Id == 75))
2973 {
2974 // cancel wand shoot
2975 if (autoRepeatSpellInfo->Id != 75)
2977 return;
2978 }
2979
2980 // castroutine
2982 {
2983 // Check if able to cast
2984 SpellCastResult result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true);
2985 if (result != SPELL_CAST_OK)
2986 {
2987 if (autoRepeatSpellInfo->Id != 75)
2989 else if (GetTypeId() == TYPEID_PLAYER)
2990 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_SpellVisual, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_castId, result);
2991
2992 return;
2993 }
2994
2995 // we want to shoot
2996 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_IGNORE_GCD);
2998 }
2999}
3000
3002{
3003 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3004
3005 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
3006
3007 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
3008 return;
3009
3010 // special breakage effects:
3011 switch (CSpellType)
3012 {
3014 {
3016
3017 // generic spells always break channeled not delayed spells
3022
3023 // autorepeat breaking
3025 {
3026 // break autorepeat if not Auto Shot
3027 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
3029 }
3030 if (pSpell->GetCastTime() > 0)
3032
3033 break;
3034 }
3036 {
3037 // channel spells always break generic non-delayed and any channeled spells
3040
3041 // it also does break autorepeat if not Auto Shot
3043 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
3046
3047 break;
3048 }
3050 {
3051 if (m_currentSpells[CSpellType] && m_currentSpells[CSpellType]->getState() == SPELL_STATE_IDLE)
3052 m_currentSpells[CSpellType]->setState(SPELL_STATE_FINISHED);
3053
3054 // only Auto Shoot does not break anything
3055 if (pSpell->GetSpellInfo()->Id != 75)
3056 {
3057 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3060 }
3061
3062 break;
3063 }
3064 default:
3065 break; // other spell types don't break anything now
3066 }
3067
3068 // current spell (if it is still here) may be safely deleted now
3069 if (m_currentSpells[CSpellType])
3070 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3071
3072 // set new current spell
3073 m_currentSpells[CSpellType] = pSpell;
3074 pSpell->SetReferencedFromCurrent(true);
3075
3076 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3077}
3078
3079void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
3080{
3081 //TC_LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
3082 Spell* spell = m_currentSpells[spellType];
3083 if (spell
3084 && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
3085 && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING))
3086 {
3087 // for example, do not let self-stun aura interrupt itself
3088 if (!spell->IsInterruptable())
3089 return;
3090
3091 // send autorepeat cancel message for autorepeat spells
3092 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3093 if (GetTypeId() == TYPEID_PLAYER)
3095
3096 if (spell->getState() != SPELL_STATE_FINISHED)
3097 spell->cancel();
3098 else
3099 {
3100 m_currentSpells[spellType] = nullptr;
3101 spell->SetReferencedFromCurrent(false);
3102 }
3103
3104 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
3105 ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo());
3106 }
3107}
3108
3109void Unit::FinishSpell(CurrentSpellTypes spellType, SpellCastResult result /*= SPELL_CAST_OK*/)
3110{
3111 Spell* spell = m_currentSpells[spellType];
3112 if (!spell)
3113 return;
3114
3115 if (spellType == CURRENT_CHANNELED_SPELL)
3116 spell->SendChannelUpdate(0, result);
3117
3118 spell->finish(result);
3119}
3120
3121bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
3122{
3123 // We don't do loop here to explicitly show that melee spell is excluded.
3124 // Maybe later some special spells will be excluded too.
3125
3126 // generic spells are cast when they are not finished and not delayed
3129 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
3130 {
3131 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3132 {
3133 if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3134 return true;
3135 }
3136 }
3137 // channeled spells may be delayed, but they are still considered cast
3138 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3140 {
3141 if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3142 return true;
3143 }
3144 // autorepeat spells may be finished or delayed, but they are still considered cast
3145 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3146 return true;
3147
3148 return false;
3149}
3150
3151void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3152{
3153 // generic spells are interrupted if they are not finished or delayed
3154 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3155 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3156
3157 // autorepeat spells are interrupted if they are not finished or delayed
3158 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3159 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3160
3161 // channeled spells are interrupted if they are not finished, even if they are delayed
3162 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3164}
3165
3167{
3168 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3169 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
3170 return m_currentSpells[i];
3171 return nullptr;
3172}
3173
3175{
3176 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3177 return spell->GetCastTime();
3178 return 0;
3179}
3180
3182{
3183 // can always move when not casting
3185 return false;
3186
3188 if (CanCastSpellWhileMoving(spell->GetSpellInfo()) || spell->getState() == SPELL_STATE_FINISHED ||
3189 !spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
3190 return false;
3191
3192 // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
3194 if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
3195 if (spell->GetSpellInfo()->IsMoveAllowedChannel() || CanCastSpellWhileMoving(spell->GetSpellInfo()))
3196 return false;
3197
3198 // prohibit movement for all other spell casts
3199 return true;
3200}
3201
3202bool Unit::CanCastSpellWhileMoving(SpellInfo const* spellInfo) const
3203{
3205 return false;
3206
3208 return true;
3209
3211 return true;
3212
3213 for (uint32 label : spellInfo->Labels)
3215 return true;
3216
3217 return false;
3218}
3219
3220bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3221{
3222 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3223}
3224
3225bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3226{
3227 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3228}
3229
3231{
3232 // Aquatic creatures are not allowed to leave liquids
3233 if (!IsInWater() && c->IsAquatic())
3234 return false;
3235
3236 // Underwater special case. Some creatures may not go below liquid surfaces
3237 if (IsUnderWater() && c->CannotPenetrateWater())
3238 return false;
3239
3240 // Water checks
3241 if (IsInWater() && !c->CanEnterWater())
3242 return false;
3243
3244 // Some creatures are tied to the ocean floor and cannot chase swimming targets.
3246 return false;
3247
3248 return true;
3249}
3250
3252{
3254}
3255
3257{
3259}
3260
3262{
3264}
3265
3267{
3268 ZLiquidStatus oldLiquidStatus = GetLiquidStatus();
3270 ProcessTerrainStatusUpdate(oldLiquidStatus, data.liquidInfo);
3272}
3273
3275{
3276 if (!IsControlledByPlayer())
3277 return;
3278
3279 // remove appropriate auras if we are swimming/not swimming respectively
3280 if (IsInWater())
3282 else
3284
3285 // liquid aura handling
3286 LiquidTypeEntry const* curLiquid = nullptr;
3287 if (IsInWater() && newLiquidData)
3288 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3289 if (curLiquid != _lastLiquid)
3290 {
3294
3295 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3296 _lastLiquid = curLiquid;
3297
3298 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3299 CastSpell(this, curLiquid->SpellID, true);
3300 }
3301
3302 // mount capability depends on liquid state change
3303 if (oldLiquidStatus != GetLiquidStatus())
3305}
3306
3308{
3310}
3311
3313{
3314 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3315
3316 // Check if these can stack anyway
3317 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3318 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3319
3320 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3321 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3322 {
3323 // check if cast item changed
3324 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3325
3326 // find current aura from spell and change it's stackamount, or refresh it's duration
3327 if (Aura* foundAura = GetOwnedAura(createInfo.GetSpellInfo()->Id, createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters() ? ObjectGuid::Empty : createInfo.CasterGUID, createInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0))
3328 {
3329 // effect masks do not match
3330 // extremely rare case
3331 // let's just recreate aura
3332 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3333 return nullptr;
3334
3335 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3336 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3337 {
3338 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3339 if (!auraEff)
3340 continue;
3341
3342 int32 bp;
3343 if (createInfo.BaseAmount)
3344 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3345 else
3346 bp = int32(spellEffectInfo.BasePoints);
3347
3348 int32* oldBP = const_cast<int32*>(&(auraEff->m_baseAmount));
3349 if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::AuraPointsStack))
3350 *oldBP += bp;
3351 else
3352 *oldBP = bp;
3353 }
3354
3355 // correct cast item guid if needed
3356 if (castItemGUID != foundAura->GetCastItemGUID())
3357 {
3358 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3359 *oldGUID = castItemGUID;
3360 uint32* oldItemId = const_cast<uint32*>(&foundAura->m_castItemId);
3361 *oldItemId = createInfo.CastItemId;
3362 int32* oldItemLevel = const_cast<int32*>(&foundAura->m_castItemLevel);
3363 *oldItemLevel = createInfo.CastItemLevel;
3364 }
3365
3366 // try to increase stack amount
3367 foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3368 return foundAura;
3369 }
3370 }
3371
3372 return nullptr;
3373}
3374
3375void Unit::_AddAura(UnitAura* aura, Unit* caster)
3376{
3378 m_ownedAuras.emplace(aura->GetId(), aura);
3379
3380 _RemoveNoStackAurasDueToAura(aura, true);
3381
3382 if (aura->IsRemoved())
3383 return;
3384
3385 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3386 if (aura->IsSingleTarget())
3387 {
3389 /* @HACK: Player is not in world during loading auras.
3390 * Single target auras are not saved or loaded from database
3391 * but may be created as a result of aura links.
3392 */
3393
3394 std::vector<Aura*> aurasSharingLimit;
3395 // remove other single target auras
3396 for (Aura* scAura : caster->GetSingleCastAuras())
3397 if (scAura->IsSingleTargetWith(aura))
3398 aurasSharingLimit.push_back(scAura);
3399
3400 // register single target aura
3401 caster->GetSingleCastAuras().push_front(aura);
3402
3403 uint32 maxOtherAuras = aura->GetSpellInfo()->MaxAffectedTargets - 1;
3404 while (aurasSharingLimit.size() > maxOtherAuras)
3405 {
3406 aurasSharingLimit.back()->Remove();
3407 aurasSharingLimit.pop_back();
3408 }
3409 }
3410}
3411
3412// creates aura application instance and registers it in lists
3413// aura application effects are handled separately to prevent aura list corruption
3415{
3416 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3418
3419 // just return if the aura has been already removed
3420 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3421 if (aura->IsRemoved())
3422 {
3423 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());
3424 return nullptr;
3425 }
3426
3427 // aura mustn't be already applied on target
3428 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3429
3430 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3431 uint32 aurId = aurSpellInfo->Id;
3432
3433 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3434 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3435 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3436 return nullptr;
3437
3438 Unit* caster = aura->GetCaster();
3439
3440 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3441 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3442
3443 if (aurSpellInfo->HasAnyAuraInterruptFlag())
3444 {
3445 m_interruptableAuras.push_front(aurApp);
3446 AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2);
3447 }
3448
3449 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3450 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3451
3452 aura->_ApplyForTarget(this, caster, aurApp);
3453 return aurApp;
3454}
3455
3456void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3457{
3458 ASSERT(aura);
3459 ASSERT(aura->HasEffect(effIndex));
3461 ASSERT(aurApp);
3462 if (!aurApp->GetEffectMask())
3463 _ApplyAura(aurApp, 1 << effIndex);
3464 else
3465 aurApp->_HandleEffect(effIndex, true);
3466}
3467
3468// handles effects of aura application
3469// should be done after registering aura in lists
3471{
3472 Aura* aura = aurApp->GetBase();
3473
3474 _RemoveNoStackAurasDueToAura(aura, false);
3475
3476 if (aurApp->GetRemoveMode())
3477 return;
3478
3479 // Update target aura state flag
3480 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3481 {
3482 uint32 aStateMask = (1 << (aState - 1));
3483 // force update so the new caster registers it
3484 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && *m_unitData->AuraState & aStateMask)
3486 else
3487 ModifyAuraState(aState, true);
3488 }
3489
3490 if (aurApp->GetRemoveMode())
3491 return;
3492
3493 // Sitdown on apply aura req seated
3496
3497 Unit* caster = aura->GetCaster();
3498
3499 if (aurApp->GetRemoveMode())
3500 return;
3501
3502 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3503
3504 // apply effects of the aura
3505 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3506 {
3507 if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
3508 aurApp->_HandleEffect(i, true);
3509 }
3510
3511 if (Player* player = ToPlayer())
3512 {
3513 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3514 player->UpdateVisibleObjectInteractions(false, true, false, false);
3515
3516 player->FailCriteria(CriteriaFailEvent::GainAura, aurApp->GetBase()->GetId());
3517 player->StartCriteria(CriteriaStartEvent::GainAura, aurApp->GetBase()->GetId());
3518 player->UpdateCriteria(CriteriaType::GainAura, aurApp->GetBase()->GetId());
3519 }
3520}
3521
3522// removes aura application from lists and unapplies effects
3523void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3524{
3525 AuraApplication * aurApp = i->second;
3526 ASSERT(aurApp);
3527 ASSERT(!aurApp->GetRemoveMode());
3528 ASSERT(aurApp->GetTarget() == this);
3529
3530 aurApp->SetRemoveMode(removeMode);
3531 Aura* aura = aurApp->GetBase();
3532 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3533
3534 // dead loop is killing the server probably
3535 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3536
3538
3539 Unit* caster = aura->GetCaster();
3540
3541 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3542 m_appliedAuras.erase(i);
3543
3545 {
3548 }
3549
3550 bool auraStateFound = false;
3551 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3552 if (auraState)
3553 {
3554 bool canBreak = false;
3555 // Get mask of all aurastates from remaining auras
3556 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3557 {
3558 if (itr->second == aurApp)
3559 {
3560 m_auraStateAuras.erase(itr);
3561 itr = m_auraStateAuras.lower_bound(auraState);
3562 canBreak = true;
3563 continue;
3564 }
3565 auraStateFound = true;
3566 ++itr;
3567 }
3568 }
3569
3570 aurApp->_Remove();
3571 aura->_UnapplyForTarget(this, caster, aurApp);
3572
3573 // remove effects of the spell - needs to be done after removing aura from lists
3574 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3575 {
3576 if (aurApp->HasEffect(itr))
3577 aurApp->_HandleEffect(itr, false);
3578 }
3579
3580 // all effect mustn't be applied
3581 ASSERT(!aurApp->GetEffectMask());
3582
3583 // Remove totem at next update if totem loses its aura
3584 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3585 {
3586 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3588 }
3589
3590 // Remove aurastates only if needed and were not found
3591 if (auraState)
3592 {
3593 if (!auraStateFound)
3594 ModifyAuraState(auraState, false);
3595 else
3596 {
3597 // update for casters, some shouldn't 'see' the aura state
3598 uint32 aStateMask = (1 << (auraState - 1));
3599 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3601 }
3602 }
3603
3604 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3605
3606 if (Player* player = ToPlayer())
3607 {
3608 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3609 player->UpdateVisibleObjectInteractions(false, true, false, false);
3610
3611 player->FailCriteria(CriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId());
3612 }
3613
3614 i = m_appliedAuras.begin();
3615}
3616
3618{
3619 // aura can be removed from unit only if it's applied on it, shouldn't happen
3620 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3621
3622 uint32 spellId = aurApp->GetBase()->GetId();
3623 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3624
3625 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3626 {
3627 if (iter->second == aurApp)
3628 {
3629 _UnapplyAura(iter, removeMode);
3630 return;
3631 }
3632 else
3633 ++iter;
3634 }
3635 ABORT();
3636}
3637
3639{
3640 SpellInfo const* spellProto = aura->GetSpellInfo();
3641
3642 // passive spell special case (only non stackable with ranks)
3643 if (spellProto->IsPassiveStackableWithRanks())
3644 return;
3645
3646 if (!IsHighestExclusiveAura(aura))
3647 {
3648 aura->Remove();
3649 return;
3650 }
3651
3652 if (owned)
3653 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3654 else
3655 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3656}
3657
3659{
3660 if (apply)
3661 {
3662 m_modAuras[aurEff->GetAuraType()].push_front(aurEff);
3663 if (Player* player = ToPlayer())
3664 {
3665 player->StartCriteria(CriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType());
3666 player->FailCriteria(CriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType());
3667 }
3668 }
3669 else
3671}
3672
3673// All aura base removes should go through this function!
3674void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3675{
3676 Aura* aura = i->second;
3677 ASSERT(!aura->IsRemoved());
3678
3679 // if unit currently update aura list then make safe update iterator shift to next
3680 if (m_auraUpdateIterator == i)
3682
3683 m_ownedAuras.erase(i);
3684 m_removedAuras.push_front(aura);
3685
3686 // Unregister single target aura
3687 if (aura->IsSingleTarget())
3688 aura->UnregisterSingleTarget();
3689
3690 aura->_Remove(removeMode);
3691
3692 i = m_ownedAuras.begin();
3693}
3694
3695void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3696{
3697 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3698 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3699 {
3700 RemoveOwnedAura(itr, removeMode);
3701 itr = m_ownedAuras.lower_bound(spellId);
3702 }
3703 else
3704 ++itr;
3705}
3706
3708{
3709 if (aura->IsRemoved())
3710 return;
3711
3712 ASSERT(aura->GetOwner() == this);
3713
3714 if (removeMode == AURA_REMOVE_NONE)
3715 {
3716 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3717 return;
3718 }
3719
3720 uint32 spellId = aura->GetId();
3721 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3722
3723 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3724 {
3725 if (itr->second == aura)
3726 {
3727 RemoveOwnedAura(itr, removeMode);
3728 return;
3729 }
3730 }
3731
3732 ABORT();
3733}
3734
3735Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, Aura* except) const
3736{
3737 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3738 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3739 {
3740 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3741 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3742 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3743 && (!except || except != itr->second))
3744 {
3745 return itr->second;
3746 }
3747 }
3748 return nullptr;
3749}
3750
3751void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3752{
3753 AuraApplication * aurApp = i->second;
3754 // Do not remove aura which is already being removed
3755 if (aurApp->GetRemoveMode())
3756 return;
3757 Aura* aura = aurApp->GetBase();
3758 _UnapplyAura(i, mode);
3759 // Remove aura - for Area and Target auras
3760 if (aura->GetOwner() == this)
3761 aura->Remove(mode);
3762}
3763
3764void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint32 reqEffMask, AuraRemoveMode removeMode)
3765{
3766 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3767 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3768 {
3769 Aura const* aura = iter->second->GetBase();
3770 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3771 && (!caster || aura->GetCasterGUID() == caster))
3772 {
3773 RemoveAura(iter, removeMode);
3774 return;
3775 }
3776 else
3777 ++iter;
3778 }
3779}
3780
3782{
3783 // we've special situation here, RemoveAura called while during aura removal
3784 // this kind of call is needed only when aura effect removal handler
3785 // or event triggered by it expects to remove
3786 // not yet removed effects of an aura
3787 if (aurApp->GetRemoveMode())
3788 {
3789 // remove remaining effects of an aura
3790 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3791 {
3792 if (aurApp->HasEffect(itr))
3793 aurApp->_HandleEffect(itr, false);
3794 }
3795 return;
3796 }
3797 // no need to remove
3798 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3799 return;
3800
3801 uint32 spellId = aurApp->GetBase()->GetId();
3802 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3803
3804 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3805 {
3806 if (aurApp == iter->second)
3807 {
3808 RemoveAura(iter, mode);
3809 return;
3810 }
3811 else
3812 ++iter;
3813 }
3814}
3815
3817{
3818 if (aura->IsRemoved())
3819 return;
3820 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3821 RemoveAura(aurApp, mode);
3822}
3823
3824void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3825{
3826 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3827 {
3828 if (check(iter->second))
3829 {
3830 RemoveAura(iter, removeMode);
3831 continue;
3832 }
3833 ++iter;
3834 }
3835}
3836
3837void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3838{
3839 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3840 {
3841 if (check(iter->second))
3842 {
3843 RemoveOwnedAura(iter, removeMode);
3844 continue;
3845 }
3846 ++iter;
3847 }
3848}
3849
3850void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3851{
3852 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3853 {
3854 if (check(iter->second))
3855 {
3856 RemoveAura(iter, removeMode);
3857 iter = m_appliedAuras.lower_bound(spellId);
3858 continue;
3859 }
3860 ++iter;
3861 }
3862}
3863
3864void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3865{
3866 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3867 {
3868 if (check(iter->second))
3869 {
3870 RemoveOwnedAura(iter, removeMode);
3871 iter = m_ownedAuras.lower_bound(spellId);
3872 continue;
3873 }
3874 ++iter;
3875 }
3876}
3877
3878void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3879{
3880 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3881 {
3882 Aura* aura = (*iter)->GetBase();
3884 ASSERT(aurApp);
3885
3886 ++iter;
3887 if (check(aurApp))
3888 {
3889 uint32 removedAuras = m_removedAurasCount;
3890 RemoveAura(aurApp, removeMode);
3891 if (m_removedAurasCount > removedAuras + 1)
3892 iter = m_modAuras[auraType].begin();
3893 }
3894 }
3895}
3896
3897void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3898{
3899 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3900 {
3901 Aura const* aura = iter->second->GetBase();
3902 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3903 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3904 {
3905 RemoveAura(iter, removeMode);
3906 iter = m_appliedAuras.lower_bound(spellId);
3907 }
3908 else
3909 ++iter;
3910 }
3911}
3912
3913void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode, uint16 num)
3914{
3915 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3916 for (AuraMap::iterator iter = range.first; iter != range.second;)
3917 {
3918 Aura* aura = iter->second;
3919 if ((aura->GetType() == UNIT_AURA_TYPE)
3920 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3921 {
3922 aura->ModStackAmount(-num, removeMode);
3923 return;
3924 }
3925 else
3926 ++iter;
3927 }
3928}
3929
3930void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
3931{
3932 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3933 for (AuraMap::iterator iter = range.first; iter != range.second;)
3934 {
3935 Aura* aura = iter->second;
3936 if (aura->GetCasterGUID() == casterGUID)
3937 {
3938 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
3939
3940 // Call OnDispel hook on AuraScript
3941 aura->CallScriptDispel(&dispelInfo);
3942
3945 else
3947
3948 // Call AfterDispel hook on AuraScript
3949 aura->CallScriptAfterDispel(&dispelInfo);
3950
3951 return;
3952 }
3953 else
3954 ++iter;
3955 }
3956}
3957
3958void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges /*= 1*/)
3959{
3960 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3961 for (AuraMap::iterator iter = range.first; iter != range.second;)
3962 {
3963 Aura* aura = iter->second;
3964 if (aura->GetCasterGUID() == casterGUID)
3965 {
3966 int32 damage[MAX_SPELL_EFFECTS];
3967 int32 baseDamage[MAX_SPELL_EFFECTS];
3968 uint32 effMask = 0;
3969 uint32 recalculateMask = 0;
3970 Unit* caster = aura->GetCaster();
3971 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3972 {
3973 if (aura->GetEffect(i))
3974 {
3975 baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
3976 damage[i] = aura->GetEffect(i)->GetAmount();
3977 effMask |= 1 << i;
3978 if (aura->GetEffect(i)->CanBeRecalculated())
3979 recalculateMask |= 1 << i;
3980 }
3981 else
3982 {
3983 baseDamage[i] = 0;
3984 damage[i] = 0;
3985 }
3986 }
3987
3989 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
3990 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
3991
3992 if (Unit* unitStealer = stealer->ToUnit())
3993 {
3994 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
3995 {
3996 if (stealCharge)
3997 oldAura->ModCharges(stolenCharges);
3998 else
3999 oldAura->ModStackAmount(stolenCharges);
4000 oldAura->SetDuration(int32(dur));
4001 }
4002 else
4003 {
4004 // single target state must be removed before aura creation to preserve existing single target aura
4005 if (aura->IsSingleTarget())
4006 aura->UnregisterSingleTarget();
4007
4008 AuraCreateInfo createInfo(aura->GetCastId(), aura->GetSpellInfo(), aura->GetCastDifficulty(), effMask, unitStealer);
4009 createInfo
4011 .SetBaseAmount(baseDamage);
4012
4013 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
4014 {
4015 // created aura must not be single target aura,, so stealer won't loose it on recast
4016 if (newAura->IsSingleTarget())
4017 {
4018 newAura->UnregisterSingleTarget();
4019 // bring back single target aura status to the old aura
4020 aura->SetIsSingleTarget(true);
4021 caster->GetSingleCastAuras().push_front(aura);
4022 }
4023 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
4024 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), stolenCharges, recalculateMask, &damage[0]);
4025 newAura->ApplyForTargets();
4026 }
4027 }
4028 }
4029
4030 if (stealCharge)
4031 aura->ModCharges(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4032 else
4033 aura->ModStackAmount(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4034
4035 return;
4036 }
4037 else
4038 ++iter;
4039 }
4040}
4041
4043{
4044 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
4045 {
4046 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
4047 {
4048 RemoveAura(iter);
4049 iter = m_appliedAuras.lower_bound(spellId);
4050 }
4051 else
4052 ++iter;
4053 }
4054}
4055
4056void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
4057{
4058 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
4059 {
4060 Aura* aura = (*iter)->GetBase();
4062 ASSERT(aurApp);
4063
4064 ++iter;
4065 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4066 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
4067 {
4068 uint32 removedAuras = m_removedAurasCount;
4069 RemoveAura(aurApp);
4070 if (m_removedAurasCount > removedAuras + 1)
4071 iter = m_modAuras[auraType].begin();
4072 }
4073 }
4074}
4075
4077{
4078 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4079 {
4080 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
4081 if (spell->Attributes & flags)
4082 RemoveAura(iter);
4083 else
4084 ++iter;
4085 }
4086}
4087
4088void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
4089{
4090 // single target auras from other casters
4091 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
4092 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
4093 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
4094 // leading to assertion failures if the aura was cast on a player that can
4095 // (and is changing map at the point where this function is called).
4096 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
4097 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
4098 // to register in m_appliedAuras
4099 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4100 {
4101 Aura const* aura = iter->second;
4102
4103 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
4104 {
4105 if (!onPhaseChange)
4106 RemoveOwnedAura(iter);
4107 else
4108 {
4109 Unit* caster = aura->GetCaster();
4110 if (!caster || !caster->InSamePhase(this))
4111 RemoveOwnedAura(iter);
4112 else
4113 ++iter;
4114 }
4115 }
4116 else
4117 ++iter;
4118 }
4119
4120 // single target auras at other targets
4121 AuraList& scAuras = GetSingleCastAuras();
4122 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4123 {
4124 Aura* aura = *iter;
4125 if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->InSamePhase(this)))
4126 {
4127 aura->Remove();
4128 iter = scAuras.begin();
4129 }
4130 else
4131 ++iter;
4132 }
4133}
4134
4135template<typename InterruptFlag>
4136bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*auraSpellInfo*/, bool /*isChannel*/, SpellInfo const* /*interruptSource*/)
4137{
4138 return false;
4139}
4140
4141template<>
4142bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* auraSpellInfo, bool isChannel, SpellInfo const* interruptSource)
4143{
4144 switch (flag)
4145 {
4147 return unit->CanCastSpellWhileMoving(auraSpellInfo);
4150 if (interruptSource)
4151 {
4152 if (interruptSource->HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED) && auraSpellInfo->Dispel == DISPEL_STEALTH)
4153 return true;
4154
4155 if (interruptSource->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_INVISIBLE) && auraSpellInfo->Dispel == DISPEL_INVISIBILITY)
4156 return true;
4157
4158 if (interruptSource->HasAttribute(SPELL_ATTR9_ALLOW_CAST_WHILE_CHANNELING) && isChannel)
4159 return true;
4160 }
4161 break;
4162 default:
4163 break;
4164 }
4165
4166 return false;
4167}
4168
4169template <typename InterruptFlags>
4170void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source)
4171{
4172 if (!HasInterruptFlag(flag))
4173 return;
4174
4175 // interrupt auras
4176 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4177 {
4178 Aura* aura = (*iter)->GetBase();
4179 ++iter;
4180 if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag)
4181 && (!source || aura->GetId() != source->Id)
4182 && !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo(), false, source))
4183 {
4184 uint32 removedAuras = m_removedAurasCount;
4186 if (m_removedAurasCount > removedAuras + 1)
4187 iter = m_interruptableAuras.begin();
4188 }
4189 }
4190
4191 // interrupt channeled spell
4193 if (spell->getState() == SPELL_STATE_CASTING
4194 && spell->GetSpellInfo()->HasChannelInterruptFlag(flag)
4195 && (!source || spell->GetSpellInfo()->Id != source->Id)
4196 && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo(), true, source))
4198
4200}
4201
4204
4205void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID)
4206{
4207 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4208 {
4209 Aura const* aura = iter->second->GetBase();
4210 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4211 {
4212 SpellInfo const* spell = aura->GetSpellInfo();
4213 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4214 {
4215 RemoveAura(iter);
4216 continue;
4217 }
4218 }
4219 ++iter;
4220 }
4221}
4222
4224{
4225 if (withRoot)
4227
4229}
4230
4231void Unit::RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4232{
4233 std::vector<Aura*> aurasToUpdateTargets;
4234 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4235 {
4236 Aura* aura = aurApp->GetBase();
4237 if (exceptSpellId && aura->GetId() == exceptSpellId)
4238 return false;
4239
4240 uint64 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4241 if (!(appliedMechanicMask & mechanicMaskToRemove))
4242 return false;
4243
4244 // spell mechanic matches required mask for removal
4245 if ((UI64LIT(1) << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4246 return true;
4247
4248 // effect mechanic matches required mask for removal - don't remove, only update targets
4249 aurasToUpdateTargets.push_back(aura);
4250 return false;
4251 }, removeMode);
4252
4253 for (Aura* aura : aurasToUpdateTargets)
4254 {
4255 aura->UpdateTargetMap(aura->GetCaster());
4256
4257 // Fully remove the aura if all effects were removed
4258 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4259 aura->Remove(removeMode);
4260 }
4261}
4262
4264{
4265 uint64 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4266 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4267 {
4268 Aura const* aura = iter->second->GetBase();
4269 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4270 {
4271 RemoveAura(iter);
4272 continue;
4273 }
4274 ++iter;
4275 }
4276}
4277
4279{
4280 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4281 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4282 {
4283 Aura* aura = iter->second;
4284 ++iter;
4285 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4286 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4287 {
4288 AuraApplication * aurApp = itr->second;
4289 ++itr;
4290 Unit* target = aurApp->GetTarget();
4291 if (target == this)
4292 continue;
4293 target->RemoveAura(aurApp);
4294 // things linked on aura remove may apply new area aura - so start from the beginning
4295 iter = m_ownedAuras.begin();
4296 }
4297 }
4298
4299 // remove area auras owned by others
4300 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4301 {
4302 if (iter->second->GetBase()->GetOwner() != this)
4303 {
4304 RemoveAura(iter);
4305 }
4306 else
4307 ++iter;
4308 }
4309}
4310
4312{
4313 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4314 // we want to have all auras removed, so use your brain when linking events
4315 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4316 {
4317 AuraApplicationMap::iterator aurAppIter;
4318 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4320
4321 AuraMap::iterator aurIter;
4322 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4323 RemoveOwnedAura(aurIter);
4324
4325 const int maxIteration = 50;
4326 // give this loop a few tries, if there are still auras then log as much information as possible
4327 if (counter >= maxIteration)
4328 {
4329 std::stringstream sstr;
4330 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4331 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4332 sstr << GetDebugInfo() << "\n";
4333
4334 if (!m_appliedAuras.empty())
4335 {
4336 sstr << "m_appliedAuras:" << "\n";
4337
4338 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4339 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4340 }
4341
4342 if (!m_ownedAuras.empty())
4343 {
4344 sstr << "m_ownedAuras:" << "\n";
4345
4346 for (auto const& [spellId, aura] : m_ownedAuras)
4347 sstr << aura->GetDebugInfo() << "\n";
4348 }
4349
4350 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4351 ABORT_MSG("%s", sstr.str().c_str());
4352
4353 break;
4354 }
4355 }
4356}
4357
4359{
4360 // in join, remove positive buffs, on end, remove negative
4361 // used to remove positive visible auras in arenas
4362 RemoveAppliedAuras([](AuraApplication const* aurApp)
4363 {
4364 Aura const* aura = aurApp->GetBase();
4365 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_ALLOW_ENTERING_ARENA) // don't remove stances, shadowform, pally/hunter auras
4366 && !aura->IsPassive() // don't remove passive auras
4367 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD))) || // not negative death persistent auras
4368 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ENTERING_ARENA); // special marker, always remove
4369 });
4370}
4371
4373{
4374 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4375 return;
4376
4377 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4378 // don't remove clone caster on evade (to be verified)
4379 auto evadeAuraCheck = [](Aura const* aura)
4380 {
4381 if (aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
4382 return false;
4383
4384 if (aura->HasEffectType(SPELL_AURA_CLONE_CASTER))
4385 return false;
4386
4387 if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
4388 return false;
4389
4390 return true;
4391 };
4392
4393 auto evadeAuraApplicationCheck = [&evadeAuraCheck](AuraApplication const* aurApp)
4394 {
4395 return evadeAuraCheck(aurApp->GetBase());
4396 };
4397
4398 RemoveAppliedAuras(evadeAuraApplicationCheck);
4399 RemoveOwnedAuras(evadeAuraCheck);
4400}
4401
4403{
4404 // used just after dieing to remove all visible auras
4405 // and disable the mods for the passive ones
4406 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4407 {
4408 Aura const* aura = iter->second->GetBase();
4409 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4411 else
4412 ++iter;
4413 }
4414
4415 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4416 {
4417 Aura* aura = iter->second;
4418 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4420 else
4421 ++iter;
4422 }
4423}
4424
4426{
4427 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4428 {
4429 Aura const* aura = iter->second->GetBase();
4430 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4432 else
4433 ++iter;
4434 }
4435
4436 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4437 {
4438 Aura* aura = iter->second;
4439 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4441 else
4442 ++iter;
4443 }
4444}
4445
4447{
4448 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4449 {
4450 Aura const* aura = iter->second->GetBase();
4451 if (aura->GetSpellInfo()->HasAura(type))
4452 ++iter;
4453 else
4455 }
4456
4457 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4458 {
4459 Aura* aura = iter->second;
4460 if (aura->GetSpellInfo()->HasAura(type))
4461 ++iter;
4462 else
4464 }
4465}
4466
4468{
4469 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4470 {
4471 Aura const* aura = iter->second->GetBase();
4472 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4473 ++iter;
4474 else
4476 }
4477
4478 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4479 {
4480 Aura* aura = iter->second;
4481 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4482 ++iter;
4483 else
4485 }
4486}
4487
4489{
4490 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4491 {
4492 Aura* aura = iter->second;
4493 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4494 {
4495 RemoveOwnedAura(iter);
4496 continue;
4497 }
4498 ++iter;
4499 }
4500}
4501
4502void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4503{
4504 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4505 for (; range.first != range.second; ++range.first)
4506 {
4507 Aura* aura = range.first->second;
4508 if (!caster || aura->GetCasterGUID() == caster)
4509 {
4510 if (aura->GetDuration() < delaytime)
4511 aura->SetDuration(0);
4512 else
4513 aura->SetDuration(aura->GetDuration() - delaytime);
4514
4515 // update for out of range group members (on 1 slot use)
4517 }
4518 }
4519}
4520
4522{
4523 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4524 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4525}
4526
4528{
4529 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4530 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4531}
4532
4533AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4534{
4535 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4536 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4537 {
4538 if (itr->second->HasEffect(effIndex)
4539 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4540 {
4541 return itr->second->GetBase()->GetEffect(effIndex);
4542 }
4543 }
4544 return nullptr;
4545}
4546
4548{
4549 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4550 while (rankSpell)
4551 {
4552 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4553 return aurEff;
4554 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4555 }
4556 return nullptr;
4557}
4558
4559AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID) const
4560{
4561 AuraEffectList const& auras = GetAuraEffectsByType(type);
4562 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4563 {
4564 SpellInfo const* spell = (*i)->GetSpellInfo();
4565 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4566 {
4567 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4568 continue;
4569 return (*i);
4570 }
4571 }
4572 return nullptr;
4573}
4574
4575AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication * except) const
4576{
4577 return GetAuraApplication(spellId, [&](AuraApplication const* app)
4578 {
4579 Aura const* aura = app->GetBase();
4580
4581 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4582 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4583 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4584 && (!except || except != app))
4585 {
4586 return true;
4587 }
4588
4589 return false;
4590 });
4591}
4592
4593AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(AuraApplication const*)> const& predicate) const
4594{
4595 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4596 if (predicate(pair.second))
4597 return pair.second;
4598
4599 return nullptr;
4600}
4601
4602AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4603{
4604 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4605 if (predicate(pair.second->GetBase()))
4606 return pair.second;
4607
4608 return nullptr;
4609}
4610
4611AuraApplication* Unit::GetAuraApplication(std::function<bool(AuraApplication const*)> const& predicate) const
4612{
4613 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4614 if (predicate(pair.second))
4615 return pair.second;
4616
4617 return nullptr;
4618}
4619
4620AuraApplication* Unit::GetAuraApplication(std::function<bool(Aura const*)> const& predicate) const
4621{
4622 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4623 if (predicate(pair.second->GetBase()))
4624 return pair.second;
4625
4626 return nullptr;
4627}
4628
4629Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4630{
4631 AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4632 return aurApp ? aurApp->GetBase() : nullptr;
4633}
4634
4635Aura* Unit::GetAura(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4636{
4637 AuraApplication* aurApp = GetAuraApplication(spellId, predicate);
4638 return aurApp ? aurApp->GetBase() : nullptr;
4639}
4640
4641Aura* Unit::GetAura(std::function<bool(Aura const*)> const& predicate) const
4642{
4643 AuraApplication* aurApp = GetAuraApplication(predicate);
4644 return aurApp ? aurApp->GetBase() : nullptr;
4645}
4646
4647AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication* except) const
4648{
4649 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4650 while (rankSpell)
4651 {
4652 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4653 return aurApp;
4654 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4655 }
4656 return nullptr;
4657}
4658
4659Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4660{
4661 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4662 return aurApp ? aurApp->GetBase() : nullptr;
4663}
4664
4665void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4666{
4667 AuraMap const& auras = GetOwnedAuras();
4668 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4669 {
4670 Aura* aura = itr->second;
4671 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4672 if (!aurApp)
4673 continue;
4674
4675 // don't try to remove passive auras
4676 if (aura->IsPassive())
4677 continue;
4678
4679 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4680 {
4681 // do not remove positive auras if friendly target
4682 // negative auras if non-friendly
4683 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4684 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4685 continue;
4686
4687 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4688 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4689 if (!chance)
4690 continue;
4691
4692 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4693 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4694 // Polymorph instead of 1 / (5 + 1) -> 16%.
4695 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES);
4696 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4697 if (charges > 0)
4698 dispelList.emplace_back(aura, chance, charges);
4699 }
4700 }
4701}
4702
4703bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4704{
4705 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4706 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4707 {
4708 if (itr->second->HasEffect(effIndex)
4709 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4710 {
4711 return true;
4712 }
4713 }
4714 return false;
4715}
4716
4718{
4719 uint32 count = 0;
4720 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4721
4722 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4723 {
4724 if (itr->second->GetBase()->GetStackAmount() == 0)
4725 ++count;
4726 else
4727 count += (uint32)itr->second->GetBase()->GetStackAmount();
4728 }
4729
4730 return count;
4731}
4732
4733bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4734{
4735 return GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask) != nullptr;
4736}
4737
4738bool Unit::HasAura(std::function<bool(Aura const*)> const& predicate) const
4739{
4740 return GetAuraApplication(predicate) != nullptr;
4741}
4742
4743bool Unit::HasAuraType(AuraType auraType) const
4744{
4745 return (!m_modAuras[auraType].empty());
4746}
4747
4749{
4750 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4751 if (caster == eff->GetCasterGUID())
4752 return true;
4753 return false;
4754}
4755
4756bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4757{
4758 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4759 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4760 if (miscvalue == (*i)->GetMiscValue())
4761 return true;
4762 return false;
4763}
4764
4765bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4766{
4767 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4768 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4769 if ((*i)->IsAffectingSpell(affectedSpell))
4770 return true;
4771 return false;
4772}
4773
4774bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4775{
4776 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4777 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4778 if (value == (*i)->GetAmount())
4779 return true;
4780 return false;
4781}
4782
4783bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4784{
4785 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4786 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4787 return true;
4788 return false;
4789}
4790
4791template <typename InterruptFlags>
4792bool Unit::HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid) const
4793{
4794 if (!HasInterruptFlag(flag))
4795 return false;
4796
4797 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4798 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(flag) &&
4799 (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4800 return true;
4801
4802 return false;
4803}
4804
4807
4808bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
4809{
4810 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4811 {
4812 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4813 if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
4814 return true;
4815
4816 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4817 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4818 if (mechanicMask & (UI64LIT(1) << spellEffectInfo.Mechanic))
4819 return true;
4820 }
4821
4822 return false;
4823}
4824
4825bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster) const
4826{
4827 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
4828 DiminishingLevels level = GetDiminishing(diminishGroup);
4829 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4830 {
4831 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4832 if (spellInfo->GetDiminishingReturnsGroupForSpell() != diminishGroup)
4833 continue;
4834
4835 int32 existingDuration = itr->second->GetBase()->GetDuration();
4836 int32 newDuration = auraSpellInfo->GetMaxDuration();
4837 ApplyDiminishingToDuration(auraSpellInfo, newDuration, caster, level);
4838 if (newDuration > 0 && newDuration < existingDuration)
4839 return true;
4840 }
4841
4842 return false;
4843}
4844
4846{
4848 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4849 {
4850 if ((*i)->GetMiscValue() == script)
4851 if ((*i)->IsAffectingSpell(spell))
4852 return (*i);
4853 }
4854 return nullptr;
4855}
4856
4858{
4859 static const AuraType diseaseAuraTypes[] =
4860 {
4861 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4862 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4863 };
4864
4865 uint32 diseases = 0;
4866 for (AuraType aType : diseaseAuraTypes)
4867 {
4868 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4869 {
4870 // Get auras with disease dispel type by caster
4871 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4872 && (*itr)->GetCasterGUID() == casterGUID)
4873 {
4874 ++diseases;
4875
4876 if (remove)
4877 {
4878 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4879 itr = m_modAuras[aType].begin();
4880 continue;
4881 }
4882 }
4883 ++itr;
4884 }
4885 }
4886 return diseases;
4887}
4888
4890{
4891 static const AuraType diseaseAuraTypes[] =
4892 {
4896 };
4897
4898 uint32 dots = 0;
4899 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4900 {
4901 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4902 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4903 {
4904 // Get auras by caster
4905 if ((*i)->GetCasterGUID() == casterGUID)
4906 ++dots;
4907 }
4908 }
4909 return dots;
4910}
4911
4912int32 Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4913{
4914 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4915 if (mTotalAuraList.empty())
4916 return 0;
4917
4918 std::map<SpellGroup, int32> sameEffectSpellGroup;
4919 int32 modifier = 0;
4920
4921 for (AuraEffect const* aurEff : mTotalAuraList)
4922 {
4923 if (predicate(aurEff))
4924 {
4925 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4926 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4927 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4928 modifier += aurEff->GetAmount();
4929 }
4930 }
4931
4932 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
4933 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4934 modifier += itr->second;
4935
4936 return modifier;
4937}
4938
4939float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4940{
4941 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4942 if (mTotalAuraList.empty())
4943 return 1.0f;
4944
4945 std::map<SpellGroup, int32> sameEffectSpellGroup;
4946 float multiplier = 1.0f;
4947
4948 for (AuraEffect const* aurEff : mTotalAuraList)
4949 {
4950 if (predicate(aurEff))
4951 {
4952 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4953 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4954 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4955 AddPct(multiplier, aurEff->GetAmount());
4956 }
4957 }
4958
4959 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
4960 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4961 AddPct(multiplier, itr->second);
4962
4963 return multiplier;
4964}
4965
4966int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4967{
4968 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4969 if (mTotalAuraList.empty())
4970 return 0;
4971
4972 int32 modifier = 0;
4973 for (AuraEffect const* aurEff : mTotalAuraList)
4974 {
4975 if (predicate(aurEff))
4976 modifier = std::max(modifier, aurEff->GetAmount());
4977 }
4978
4979 return modifier;
4980}
4981
4982int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4983{
4984 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4985 if (mTotalAuraList.empty())
4986 return 0;
4987
4988 int32 modifier = 0;
4989 for (AuraEffect const* aurEff : mTotalAuraList)
4990 {
4991 if (predicate(aurEff))
4992 modifier = std::min(modifier, aurEff->GetAmount());
4993 }
4994
4995 return modifier;
4996}
4997
4999{
5000 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5001}
5002
5004{
5005 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5006}
5007
5009{
5010 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5011}
5012
5014{
5015 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5016}
5017
5019{
5020 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5021 {
5022 if ((aurEff->GetMiscValue() & miscMask) != 0)
5023 return true;
5024 return false;
5025 });
5026}
5027
5029{
5030 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5031 {
5032 if ((aurEff->GetMiscValue() & miscMask) != 0)
5033 return true;
5034 return false;
5035 });
5036}
5037
5038int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
5039{
5040 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
5041 {
5042 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
5043 return true;
5044 return false;
5045 });
5046}
5047
5049{
5050 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5051 {
5052 if ((aurEff->GetMiscValue() & miscMask) != 0)
5053 return true;
5054 return false;
5055 });
5056}
5057
5059{
5060 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5061 {
5062 if (aurEff->GetMiscValue() == miscValue)
5063 return true;
5064 return false;
5065 });
5066}
5067
5069{
5070 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5071 {
5072 if (aurEff->GetMiscValue() == miscValue)
5073 return true;
5074 return false;
5075 });
5076}
5077
5079{
5080 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5081 {
5082 if (aurEff->GetMiscValue() == miscValue)
5083 return true;
5084 return false;
5085 });
5086}
5087
5089{
5090 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5091 {
5092 if (aurEff->GetMiscValue() == miscValue)
5093 return true;
5094 return false;
5095 });
5096}
5097
5099{
5100 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5101 {
5102 if (aurEff->IsAffectingSpell(affectedSpell))
5103 return true;
5104 return false;
5105 });
5106}
5107
5108float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5109{
5110 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5111 {
5112 if (aurEff->IsAffectingSpell(affectedSpell))
5113 return true;
5114 return false;
5115 });
5116}
5117
5119{
5120 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5121 {
5122 if (aurEff->IsAffectingSpell(affectedSpell))
5123 return true;
5124 return false;
5125 });
5126}
5127
5129{
5130 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5131 {
5132 if (aurEff->IsAffectingSpell(affectedSpell))
5133 return true;
5134 return false;
5135 });
5136}
5137
5139{
5140 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
5141 {
5142 m_floatStatPosBuff[i] = 0.0f;
5143 m_floatStatNegBuff[i] = 0.0f;
5145 }
5146}
5147
5149{
5150 float modPos = 0.0f;
5151 float modNeg = 0.0f;
5152 float factor = 0.0f;
5153
5154 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5155
5156 // includes value from items and enchantments
5157 float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
5158 if (modValue > 0.f)
5159 modPos += modValue;
5160 else
5161 modNeg += modValue;
5162
5163 if (IsGuardian())
5164 {
5165 modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
5166 if (modValue > 0.f)
5167 modPos += modValue;
5168 else
5169 modNeg += modValue;
5170 }
5171
5172 // SPELL_AURA_MOD_STAT_BONUS_PCT only affects BASE_VALUE
5173 modPos = CalculatePct(modPos, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5174 modNeg = CalculatePct(modNeg, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5175
5176 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5177 {
5178 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
5179 return true;
5180 return false;
5181 });
5182
5183 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5184 {
5185 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5186 return true;
5187 return false;
5188 });
5189
5190 factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
5191 {
5192 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5193 return true;
5194 return false;
5195 });
5196
5197 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
5198 {
5199 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5200 return true;
5201 return false;
5202 });
5203
5204 modPos *= factor;
5205 modNeg *= factor;
5206
5207 m_floatStatPosBuff[stat] = modPos;
5208 m_floatStatNegBuff[stat] = modNeg;
5209
5211}
5212
5214{
5217}
5218
5220{
5221 m_dynObj.push_back(dynObj);
5222 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5224}
5225
5227{
5228 std::erase(m_dynObj, dynObj);
5229 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5231}
5232
5234{
5235 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5236 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5237}
5238
5239std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5240{
5241 std::vector<DynamicObject*> dynamicobjects;
5242 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5243 if ((*i)->GetSpellId() == spellId)
5244 dynamicobjects.push_back(*i);
5245
5246 return dynamicobjects;
5247}
5248
5250{
5251 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5252 {
5253 DynamicObject* dynObj = *i;
5254 if (dynObj->GetSpellId() == spellId)
5255 {
5256 dynObj->Remove();
5257 i = m_dynObj.begin();
5258 }
5259 else
5260 ++i;
5261 }
5262}
5263
5265{
5266 while (!m_dynObj.empty())
5267 m_dynObj.back()->Remove();
5268}
5269
5271{
5272 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5273 return gameobjects.empty() ? nullptr : gameobjects.front();
5274}
5275
5276std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5277{
5278 std::vector<GameObject*> gameobjects;
5279 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5280 if ((*i)->GetSpellId() == spellId)
5281 gameobjects.push_back(*i);
5282
5283 return gameobjects;
5284}
5285
5287{
5288 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5289 return;
5290
5291 m_gameObj.push_back(gameObj);
5292 gameObj->SetOwnerGUID(GetGUID());
5293
5294 if (gameObj->GetSpellId())
5295 {
5296 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId(), GetMap()->GetDifficultyID());
5297 // Need disable spell use for owner
5298 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5299 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5300 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5301 }
5302
5304 ToCreature()->AI()->JustSummonedGameobject(gameObj);
5305}
5306
5307void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5308{
5309 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5310 return;
5311
5313
5314 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
5315 {
5316 if (m_ObjectSlot[i] == gameObj->GetGUID())
5317 {
5318 m_ObjectSlot[i].Clear();
5319 break;
5320 }
5321 }
5322
5323 // GO created by some spell
5324 if (uint32 spellid = gameObj->GetSpellId())
5325 {
5326 RemoveAurasDueToSpell(spellid);
5327
5328 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid, GetMap()->GetDifficultyID());
5329 // Need activate spell use for owner
5330 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5331 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5332 GetSpellHistory()->SendCooldownEvent(createBySpell);
5333 }
5334
5335 m_gameObj.remove(gameObj);
5336
5339
5340 if (del)
5341 {
5342 gameObj->SetRespawnTime(0);
5343 gameObj->Delete();
5344 }
5345}
5346
5347void Unit::RemoveGameObject(uint32 spellid, bool del)
5348{
5349 if (m_gameObj.empty())
5350 return;
5351 GameObjectList::iterator i, next;
5352 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
5353 {
5354 next = i;
5355 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5356 {
5357 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5358 if (del)
5359 {
5360 (*i)->SetRespawnTime(0);
5361 (*i)->Delete();
5362 }
5363
5364 next = m_gameObj.erase(i);
5365 }
5366 else
5367 ++next;
5368 }
5369}
5370
5372{
5373 // remove references to unit
5374 while (!m_gameObj.empty())
5375 {
5376 GameObjectList::iterator i = m_gameObj.begin();
5377 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5378 (*i)->SetRespawnTime(0);
5379 (*i)->Delete();
5380 m_gameObj.erase(i);
5381 }
5382}
5383
5385{
5386 m_areaTrigger.push_back(areaTrigger);
5387 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5388 ToCreature()->AI()->JustRegisteredAreaTrigger(areaTrigger);
5389}
5390
5392{
5393 std::erase(m_areaTrigger, areaTrigger);
5394 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5395 ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger);
5396}
5397
5399{
5400 std::vector<AreaTrigger*> areaTriggers = GetAreaTriggers(spellId);
5401 return areaTriggers.empty() ? nullptr : areaTriggers.front();
5402}
5403
5404std::vector<AreaTrigger*> Unit::GetAreaTriggers(uint32 spellId) const
5405{
5406 std::vector<AreaTrigger*> areaTriggers;
5407 for (AreaTriggerList::const_iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end(); ++i)
5408 if ((*i)->GetSpellId() == spellId)
5409 areaTriggers.push_back(*i);
5410
5411 return areaTriggers;
5412}
5413
5415{
5416 for (AreaTriggerList::iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end();)
5417 {
5418 AreaTrigger* areaTrigger = *i;
5419 if (areaTrigger->GetSpellId() == spellId)
5420 {
5421 areaTrigger->Remove();
5422 i = m_areaTrigger.begin();
5423 }
5424 else
5425 ++i;
5426 }
5427}
5428
5430{
5431 for (AreaTrigger* areaTrigger : m_areaTrigger)
5432 {
5433 if (areaTrigger->GetAuraEffect() == aurEff)
5434 {
5435 areaTrigger->Remove();
5436 break; // There can only be one AreaTrigger per AuraEffect
5437 }
5438 }
5439}
5440
5442{
5443 while (!m_areaTrigger.empty())
5444 m_areaTrigger.back()->Remove();
5445}
5446
5448{
5450 packet.Me = log->target->GetGUID();
5451 packet.CasterGUID = log->attacker ? log->attacker->GetGUID() : ObjectGuid::Empty;
5452 packet.CastID = log->castId;
5453 packet.SpellID = log->Spell ? log->Spell->Id : 0;
5454 packet.Visual = log->SpellVisual;
5455 packet.Damage = log->damage;
5456 packet.OriginalDamage = log->originalDamage;
5457 if (log->damage > log->preHitHealth)
5458 packet.Overkill = log->damage - log->preHitHealth;
5459 else
5460 packet.Overkill = -1;
5461
5462 packet.SchoolMask = log->schoolMask;
5463 packet.Absorbed = log->absorb;
5464 packet.Resisted = log->resist;
5465 packet.ShieldBlock = log->blocked;
5466 packet.Periodic = log->periodicLog;
5467 packet.Flags = log->HitInfo;
5468
5470 if (contentTuningParams.GenerateDataForUnits(log->attacker, log->target))
5471 packet.ContentTuning = contentTuningParams;
5472
5473 SendCombatLogMessage(&packet);
5474}
5475
5476/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget,
5477 ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
5478 Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5479{
5480 static constexpr int32 ProcChainHardLimit = 10;
5481 if (spell && spell->GetProcChainLength() >= ProcChainHardLimit)
5482 {
5483 TC_LOG_ERROR("spells.aura.effect", "Unit::ProcSkillsAndAuras: Possible infinite proc loop detected, current triggering spell {}", spell->GetDebugInfo().c_str());
5484 return;
5485 }
5486
5487 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5488 SpellInfo const* spellInfo = [&]() -> SpellInfo const*
5489 {
5490 if (spell)
5491 return spell->GetSpellInfo();
5492 if (damageInfo)
5493 return damageInfo->GetSpellInfo();
5494 if (healInfo)
5495 return healInfo->GetSpellInfo();
5496 return nullptr;
5497 }();
5498 if (typeMaskActor && actor && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)))
5499 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5500
5501 if (typeMaskActionTarget && actionTarget && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)))
5502 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5503
5504 if (actor)
5505 actor->TriggerAurasProcOnEvent(nullptr, nullptr, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5506}
5507
5509{
5510 AuraEffect const* aura = info->auraEff;
5512 data.TargetGUID = GetGUID();
5513 data.CasterGUID = aura->GetCasterGUID();
5514 data.SpellID = aura->GetId();
5515 data.LogData.Initialize(this);
5516
5518 spellLogEffect.Effect = aura->GetAuraType();
5519 spellLogEffect.Amount = info->damage;
5520 spellLogEffect.OriginalDamage = info->originalDamage;
5521 spellLogEffect.OverHealOrKill = info->overDamage;
5522 spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask();
5523 spellLogEffect.AbsorbedOrAmplitude = info->absorb;
5524 spellLogEffect.Resisted = info->resist;
5525 spellLogEffect.Crit = info->critical;
5527
5529 if (Unit* caster = ObjectAccessor::GetUnit(*this, aura->GetCasterGUID()))
5530 if (contentTuningParams.GenerateDataForUnits(caster, this))
5531 spellLogEffect.ContentTuning = contentTuningParams;
5532
5533 data.Effects.push_back(spellLogEffect);
5534
5535 SendCombatLogMessage(&data);
5536}
5537
5539{
5541 procResist.Caster = GetGUID();
5542 procResist.SpellID = spellId;
5543 procResist.Target = target->GetGUID();
5544 SendMessageToSet(procResist.Write(), true);
5545}
5546
5547void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId, bool isPeriodic)
5548{
5550 spellOrDamageImmune.CasterGUID = GetGUID();
5551 spellOrDamageImmune.VictimGUID = target->GetGUID();
5552 spellOrDamageImmune.SpellID = spellId;
5553 spellOrDamageImmune.IsPeriodic = isPeriodic;
5554 SendMessageToSet(spellOrDamageImmune.Write(), true);
5555}
5556
5558{
5560 packet.HitInfo = damageInfo->HitInfo;
5561 packet.AttackerGUID = damageInfo->Attacker->GetGUID();
5562 packet.VictimGUID = damageInfo->Target->GetGUID();
5563 packet.Damage = damageInfo->Damage;
5564 packet.OriginalDamage = damageInfo->OriginalDamage;
5565 int32 overkill = damageInfo->Damage - damageInfo->Target->GetHealth();
5566 packet.OverDamage = (overkill < 0 ? -1 : overkill);
5567
5568 packet.SubDmg.emplace();
5569 packet.SubDmg->SchoolMask = damageInfo->DamageSchoolMask; // School of sub damage
5570 packet.SubDmg->FDamage = damageInfo->Damage; // sub damage
5571 packet.SubDmg->Damage = damageInfo->Damage; // Sub Damage
5572 packet.SubDmg->Absorbed = damageInfo->Absorb;
5573 packet.SubDmg->Resisted = damageInfo->Resist;
5574
5575 packet.VictimState = damageInfo->TargetState;
5576 packet.BlockAmount = damageInfo->Blocked;
5577 packet.RageGained = damageInfo->RageGained;
5578
5579 packet.LogData.Initialize(damageInfo->Attacker);
5580
5582 if (contentTuningParams.GenerateDataForUnits(damageInfo->Attacker, damageInfo->Target))
5583 packet.ContentTuning = contentTuningParams;
5584
5585 SendCombatLogMessage(&packet);
5586}
5587
5588void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount, uint32 RageGained)
5589{
5590 CalcDamageInfo dmgInfo;
5591 dmgInfo.HitInfo = HitInfo;
5592 dmgInfo.Attacker = this;
5593 dmgInfo.Target = target;
5594 dmgInfo.Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5595 dmgInfo.OriginalDamage = Damage;
5596 dmgInfo.DamageSchoolMask = damageSchoolMask;
5597 dmgInfo.Absorb = AbsorbDamage;
5598 dmgInfo.Resist = Resist;
5599 dmgInfo.TargetState = TargetState;
5600 dmgInfo.Blocked = BlockedAmount;
5601 dmgInfo.RageGained = RageGained;
5602 SendAttackStateUpdate(&dmgInfo);
5603}
5604
5605void Unit::SetPowerType(Powers power, bool sendUpdate/* = true*/, bool onInit /*= false*/)
5606{
5607 if (!onInit && GetPowerType() == power)
5608 return;
5609
5610 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(power);
5611 if (!powerTypeEntry)
5612 return;
5613
5614 if (IsCreature() && !powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::IsUsedByNPCs))
5615 return;
5616
5618
5619 // Update max power
5620 UpdateMaxPower(power);
5621
5622 // Update current power
5623 if (!onInit)
5624 {
5625 switch (power)
5626 {
5627 case POWER_MANA: // Keep the same (druid form switching...)
5628 case POWER_ENERGY:
5629 break;
5630 case POWER_RAGE: // Reset to zero
5631 SetPower(POWER_RAGE, 0);
5632 break;
5633 case POWER_FOCUS: // Make it full
5634 SetFullPower(power);
5635 break;
5636 default:
5637 break;
5638 }
5639 }
5640 else
5641 SetInitialPowerValue(power);
5642
5643 if (!sendUpdate)
5644 return;
5645
5646 if (Player* thisPlayer = ToPlayer())
5647 {
5648 if (thisPlayer->GetGroup())
5649 thisPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
5650 }
5651 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
5652 {
5653 if (pet->isControlled())
5654 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
5655 }*/
5656}
5657
5659{
5660 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType);
5661 if (!powerTypeEntry)
5662 return;
5663
5664 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UnitsUseDefaultPowerOnInit))
5665 SetPower(powerType, powerTypeEntry->DefaultPower);
5666 else
5667 SetFullPower(powerType);
5668}
5669
5671{
5672 Powers displayPower = POWER_MANA;
5673 switch (GetShapeshiftForm())
5674 {
5675 case FORM_GHOUL:
5676 case FORM_CAT_FORM:
5677 displayPower = POWER_ENERGY;
5678 break;
5679 case FORM_BEAR_FORM:
5681 displayPower = POWER_RAGE;
5682 break;
5683 case FORM_TRAVEL_FORM:
5684 case FORM_GHOST_WOLF:
5685 displayPower = POWER_MANA;
5686 break;
5687 default:
5688 {
5690 if (!powerTypeAuras.empty())
5691 {
5692 AuraEffect const* powerTypeAura = powerTypeAuras.front();
5693 displayPower = Powers(powerTypeAura->GetMiscValue());
5694 }
5695 else
5696 {
5697 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5698 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5699 displayPower = Powers(cEntry->DisplayPower);
5700
5701 if (Vehicle* vehicle = GetVehicleKit())
5702 {
5703 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID[0]))
5704 displayPower = Powers(powerDisplay->ActualType);
5705 }
5706 else if (IsHunterPet())
5707 displayPower = POWER_FOCUS;
5708 }
5709 break;
5710 }
5711 }
5712
5713 return displayPower;
5714}
5715
5717{
5719}
5720
5722{
5724 if (sheathed == SHEATH_STATE_UNARMED)
5726}
5727
5728void Unit::_addAttacker(Unit* pAttacker)
5729{
5730 m_attackers.insert(pAttacker);
5731}
5732
5734{
5735 m_attackers.erase(pAttacker);
5736}
5737
5738Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5739{
5740 if (!IsEngaged())
5741 return nullptr;
5742
5743 if (Unit* victim = GetVictim())
5744 if ((!IsPet() && !GetPlayerMovingMe()) || IsInCombatWith(victim))
5745 return victim;
5746
5747 CombatManager const& mgr = GetCombatManager();
5748 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5749 Unit* owner = GetCharmerOrOwner();
5750 if (mgr.HasPvPCombat())
5751 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5752 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5753 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5754 if (mgr.HasPvECombat())
5755 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5756 if (owner && (owner->GetCombatManager().HasPvECombat()))
5757 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5758 return nullptr;
5759}
5760
5761bool Unit::Attack(Unit* victim, bool meleeAttack)
5762{
5763 if (!victim || victim == this)
5764 return false;
5765
5766 // dead units can neither attack nor be attacked
5767 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5768 return false;
5769
5770 // player cannot attack in mount state
5771 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5772 return false;
5773
5774 Creature* creature = ToCreature();
5775 // creatures cannot attack while evading
5776 if (creature && creature->IsInEvadeMode())
5777 return false;
5778
5779 // nobody can attack GM in GM-mode
5780 if (victim->GetTypeId() == TYPEID_PLAYER)
5781 {
5782 if (victim->ToPlayer()->IsGameMaster())
5783 return false;
5784 }
5785 else
5786 {
5787 if (victim->ToCreature()->IsEvadingAttacks())
5788 return false;
5789 }
5790
5791 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5794
5795 if (m_attacking)
5796 {
5797 if (m_attacking == victim)
5798 {
5799 // switch to melee attack from ranged/magic
5800 if (meleeAttack)
5801 {
5803 {
5805 SendMeleeAttackStart(victim);
5806 return true;
5807 }
5808 }
5810 {
5812 SendMeleeAttackStop(victim);
5813 return true;
5814 }
5815 return false;
5816 }
5817
5818 // switch target
5820 if (!meleeAttack)
5822 }
5823
5824 if (m_attacking)
5826
5827 m_attacking = victim;
5829
5830 // Set our target
5831 SetTarget(victim->GetGUID());
5832
5833 if (meleeAttack)
5835
5836 // set position before any AI calls/assistance
5837 //if (GetTypeId() == TYPEID_UNIT)
5838 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5839
5840 if (creature && !IsControlledByPlayer())
5841 {
5842 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5843
5845 creature->CallAssistance();
5846
5847 // Remove emote and stand state - will be restored on creature reset
5850 }
5851
5852 // delay offhand weapon attack by 50% of the base attack time
5855
5856 if (meleeAttack)
5857 SendMeleeAttackStart(victim);
5858
5859 // Let the pet know we've started attacking someting. Handles melee attacks only
5860 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5861 if (GetTypeId() == TYPEID_PLAYER)
5862 {
5863 for (Unit* controlled : m_Controlled)
5864 if (Creature* cControlled = controlled->ToCreature())
5865 if (CreatureAI* controlledAI = cControlled->AI())
5866 controlledAI->OwnerAttacked(victim);
5867 }
5868
5869 return true;
5870}
5871
5873{
5874 if (!m_attacking)
5875 return false;
5876
5877 Unit* victim = m_attacking;
5878
5880 m_attacking = nullptr;
5881
5882 // Clear our target
5884
5886
5888
5889 // reset only at real combat stop
5890 if (Creature* creature = ToCreature())
5891 {
5892 creature->SetNoCallAssistance(false);
5893 }
5894
5895 SendMeleeAttackStop(victim);
5896
5897 return true;
5898}
5899
5901{
5902 // iterate attackers
5903 UnitVector toRemove;
5904 AttackerSet const& attackers = getAttackers();
5905 for (Unit* attacker : attackers)
5906 if (!attacker->IsValidAttackTarget(this))
5907 toRemove.push_back(attacker);
5908
5909 for (Unit* attacker : toRemove)
5910 attacker->AttackStop();
5911
5912 // remove our own victim
5913 if (Unit* victim = GetVictim())
5914 if (!IsValidAttackTarget(victim))
5915 AttackStop();
5916}
5917
5918void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
5919{
5920 if (includingCast && IsNonMeleeSpellCast(false))
5922
5923 AttackStop();
5924 if (!unitFilter)
5926 else
5927 {
5928 std::vector<Unit*> attackersToRemove;
5929 attackersToRemove.reserve(m_attackers.size());
5930 std::copy_if(m_attackers.begin(), m_attackers.end(), std::back_inserter(attackersToRemove), unitFilter);
5931
5932 for (Unit* attacker : attackersToRemove)
5933 attacker->AttackStop();
5934 }
5935
5936 if (GetTypeId() == TYPEID_PLAYER)
5937 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
5938
5939 m_combatManager.EndAllPvECombat(unitFilter);
5940 if (mutualPvP)
5941 m_combatManager.EndAllPvPCombat(unitFilter);
5942 else // vanish and brethren are weird
5944}
5945
5946void Unit::CombatStopWithPets(bool includingCast)
5947{
5948 CombatStop(includingCast);
5949
5950 for (Unit* minion : m_Controlled)
5951 minion->CombatStop(includingCast);
5952}
5953
5955{
5957 return true;
5958
5959 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
5960 if ((*itr)->isAttackingPlayer())
5961 return true;
5962
5963 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
5964 if (!m_SummonSlot[i].IsEmpty())
5965 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
5966 if (summon->isAttackingPlayer())
5967 return true;
5968
5969 return false;
5970}
5971
5973{
5974 while (!m_attackers.empty())
5975 {
5976 AttackerSet::iterator iter = m_attackers.begin();
5977 if (!(*iter)->AttackStop())
5978 {
5979 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
5980 m_attackers.erase(iter);
5981 }
5982 }
5983}
5984
5986{
5987 uint32 mask = 1 << (flag - 1);
5988 if (apply)
5989 {
5990 if (!(*m_unitData->AuraState & mask))
5991 {
5993 if (GetTypeId() == TYPEID_PLAYER)
5994 {
5995 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
5996 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
5997 {
5998 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
5999 continue;
6000 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6001 if (!spellInfo || !spellInfo->IsPassive())
6002 continue;
6003 if (spellInfo->CasterAuraState == uint32(flag))
6004 CastSpell(this, itr->first, true);
6005 }
6006 }
6007 else if (Pet* pet = ToCreature()->ToPet())
6008 {
6009 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
6010 {
6011 if (itr->second.state == PETSPELL_REMOVED)
6012 continue;
6013 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6014 if (!spellInfo || !spellInfo->IsPassive())
6015 continue;
6016 if (spellInfo->CasterAuraState == uint32(flag))
6017 CastSpell(this, itr->first, true);
6018 }
6019 }
6020 }
6021 }
6022 else
6023 {
6024 if (*m_unitData->AuraState & mask)
6025 {
6027
6029 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
6030 {
6031 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
6032 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGED))
6033 RemoveAura(itr);
6034 else
6035 ++itr;
6036 }
6037 }
6038 }
6039}
6040
6042{
6043 uint32 auraStates = *m_unitData->AuraState & ~(PER_CASTER_AURA_STATE_MASK);
6044 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
6045 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
6046 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
6047 auraStates |= (1 << (itr->first - 1));
6048
6049 return auraStates;
6050}
6051
6052bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
6053{
6054 if (Caster)
6055 {
6056 if (spellProto)
6057 {
6058 if (Caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_IGNORE_AURASTATE, spellProto))
6059 return true;
6060 }
6061
6062 // Check per caster aura state
6063 // If aura with aurastate by caster not found return false
6064 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
6065 {
6066 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
6067 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
6068 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
6069 return true;
6070 return false;
6071 }
6072 }
6073
6074 return (*m_unitData->AuraState & (1 << (flag - 1))) != 0;
6075}
6076
6078{
6079 if (GetOwnerGUID() == owner)
6080 return;
6081
6083 if (!owner)
6084 return;
6085
6086 // Update owner dependent fields
6087 Player* player = ObjectAccessor::GetPlayer(*this, owner);
6088 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
6089 return;
6090
6091 UpdateData udata(GetMapId());
6092 WorldPacket packet;
6094 udata.BuildPacket(&packet);
6095 player->SendDirectMessage(&packet);
6096}
6097
6099{
6101}
6102
6104{
6106}
6107
6109{
6111 if (!guid.IsEmpty())
6112 {
6113 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
6114 return master->GetControllingPlayer();
6115 return nullptr;
6116 }
6117 else
6118 return const_cast<Player*>(ToPlayer());
6119}
6120
6122{
6123 ObjectGuid pet_guid = GetMinionGUID();
6124 if (!pet_guid.IsEmpty())
6125 {
6126 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6127 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
6128 return (Minion*)pet;
6129
6130 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
6131 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
6132 }
6133
6134 return nullptr;
6135}
6136
6138{
6139 ObjectGuid pet_guid = GetPetGUID();
6140 if (!pet_guid.IsEmpty())
6141 {
6142 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6143 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6144 return (Guardian*)pet;
6145
6146 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
6147 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
6148 }
6149
6150 return nullptr;
6151}
6152
6153void Unit::SetMinion(Minion *minion, bool apply)
6154{
6155 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
6156
6157 if (apply)
6158 {
6159 if (!minion->GetOwnerGUID().IsEmpty())
6160 {
6161 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6162 return;
6163 }
6164
6165 if (!IsInWorld())
6166 {
6167 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
6168 return;
6169 }
6170
6171 minion->SetOwnerGUID(GetGUID());
6172
6173 m_Controlled.insert(minion);
6174
6175 if (GetTypeId() == TYPEID_PLAYER)
6176 {
6177 minion->m_ControlledByPlayer = true;
6179 }
6180
6181 // Can only have one pet. If a new one is summoned, dismiss the old one.
6182 if (minion->IsGuardianPet())
6183 {
6184 if (Guardian* oldPet = GetGuardianPet())
6185 {
6186 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
6187 {
6188 // remove existing minion pet
6189 if (Pet* oldPetAsPet = oldPet->ToPet())
6190 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
6191 else
6192 oldPet->UnSummon();
6193 SetPetGUID(minion->GetGUID());
6195 }
6196 }
6197 else
6198 {
6199 SetPetGUID(minion->GetGUID());
6201 }
6202 }
6203
6205 {
6206 if (GetMinionGUID().IsEmpty())
6207 SetMinionGUID(minion->GetGUID());
6208 }
6209
6210 SummonPropertiesEntry const* properties = minion->m_Properties;
6211 if (properties && SummonTitle(properties->Title) == SummonTitle::Companion)
6212 {
6213 SetCritterGUID(minion->GetGUID());
6214 if (Player const* thisPlayer = ToPlayer())
6215 {
6217 {
6218 if (BattlePets::BattlePet const* pet = thisPlayer->GetSession()->GetBattlePetMgr()->GetPet(thisPlayer->GetSummonedBattlePetGUID()))
6219 {
6220 minion->SetBattlePetCompanionGUID(thisPlayer->GetSummonedBattlePetGUID());
6221 minion->SetBattlePetCompanionNameTimestamp(pet->NameTimestamp);
6222 minion->SetWildBattlePetLevel(pet->PacketInfo.Level);
6223
6224 if (uint32 display = pet->PacketInfo.DisplayID)
6225 minion->SetDisplayId(display, true);
6226 }
6227 }
6228 }
6229 }
6230
6231 // PvP, FFAPvP
6233
6234 // FIXME: hack, speed must be set only at follow
6235 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
6236 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
6237 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
6238
6239 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
6240 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6241
6242 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6243 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
6244 }
6245 else
6246 {
6247 if (minion->GetOwnerGUID() != GetGUID())
6248 {
6249 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6250 return;
6251 }
6252
6253 m_Controlled.erase(minion);
6254
6256 if (GetCritterGUID() == minion->GetGUID())
6258
6259 if (minion->IsGuardianPet())
6260 {
6261 if (GetPetGUID() == minion->GetGUID())
6263 }
6264 else if (minion->IsTotem())
6265 {
6266 // All summoned by totem minions must disappear when it is removed.
6267 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell(), DIFFICULTY_NONE))
6268 {
6269 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
6270 {
6271 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
6272 continue;
6273
6274 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
6275 }
6276 }
6277 }
6278
6279 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6280 // Remove infinity cooldown
6281 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6282 GetSpellHistory()->SendCooldownEvent(spellInfo);
6283
6284 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6285 {
6286 if (GetMinionGUID() == minion->GetGUID())
6287 {
6289 // Check if there is another minion
6290 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6291 {
6292 // do not use this check, creature do not have charm guid
6293 //if (GetCharmedGUID() == (*itr)->GetGUID())
6294 if (GetGUID() == (*itr)->GetCharmerGUID())
6295 continue;
6296
6297 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
6298 if ((*itr)->GetOwnerGUID() != GetGUID())
6299 {
6300 OutDebugInfo();
6301 (*itr)->OutDebugInfo();
6302 ABORT();
6303 }
6304 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
6305
6306 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
6307 continue;
6308
6309 SetMinionGUID((*itr)->GetGUID());
6310 // show another pet bar if there is no charm bar
6311 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
6312 {
6313 if ((*itr)->IsPet())
6315 else
6317 }
6318 break;
6319 }
6320 }
6321 }
6322 }
6324}
6325
6326void Unit::GetAllMinionsByEntry(std::list<TempSummon*>& Minions, uint32 entry)
6327{
6328 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6329 {
6330 Unit* unit = *itr;
6331 if (unit->GetEntry() == entry && unit->IsSummon()) // minion, actually
6332 Minions.push_back(unit->ToTempSummon());
6333 }
6334}
6335
6337{
6338 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6339 {
6340 Unit* unit = *itr;
6341 ++itr;
6342 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6343 && unit->ToCreature()->IsSummon()) // minion, actually
6344 unit->ToTempSummon()->UnSummon();
6345 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6346 }
6347}
6348
6349void Unit::SetCharm(Unit* charm, bool apply)
6350{
6351 if (apply)
6352 {
6353 if (GetTypeId() == TYPEID_PLAYER)
6354 {
6355 ASSERT(GetCharmedGUID().IsEmpty(),
6356 "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());
6358 m_charmed = charm;
6359
6360 charm->m_ControlledByPlayer = true;
6363 }
6364 else
6365 charm->m_ControlledByPlayer = false;
6366
6367 // PvP, FFAPvP
6369
6370 ASSERT(charm->GetCharmerGUID().IsEmpty(),
6371 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6373 charm->m_charmer = this;
6374
6377 charm->SetWalk(false);
6378
6379 m_Controlled.insert(charm);
6380 }
6381 else
6382 {
6384
6385 if (GetTypeId() == TYPEID_PLAYER)
6386 {
6387 ASSERT(GetCharmedGUID() == charm->GetGUID(),
6388 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6390 m_charmed = nullptr;
6391 }
6392
6393 ASSERT(charm->GetCharmerGUID() == GetGUID(),
6394 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6396 charm->m_charmer = nullptr;
6397
6398 if (charm->GetTypeId() == TYPEID_PLAYER)
6399 {
6400 charm->m_ControlledByPlayer = true;
6402 charm->ToPlayer()->UpdatePvPState();
6403 }
6404 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6405 {
6406 charm->m_ControlledByPlayer = true;
6408 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6409 }
6410 else
6411 {
6412 charm->m_ControlledByPlayer = false;
6415 }
6416
6417 if (charm->IsWalking() != _isWalkingBeforeCharm)
6419
6420 if (charm->GetTypeId() == TYPEID_PLAYER
6422 || charm->GetOwnerGUID() != GetGUID())
6423 {
6424 m_Controlled.erase(charm);
6425 }
6426 }
6428}
6429
6430/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6431{
6432 int32 gain = 0;
6433 Unit* healer = healInfo.GetHealer();
6434 Unit* victim = healInfo.GetTarget();
6435 uint32 addhealth = healInfo.GetHeal();
6436
6437 if (UnitAI* victimAI = victim->GetAI())
6438 victimAI->HealReceived(healer, addhealth);
6439
6440 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6441 healerAI->HealDone(victim, addhealth);
6442
6443 if (addhealth)
6444 gain = victim->ModifyHealth(int32(addhealth));
6445
6446 // Hook for OnHeal Event
6447 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6448
6449 Unit* unit = healer;
6450 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6451 unit = healer->GetOwner();
6452
6453 if (unit)
6454 {
6455 if (Player* player = unit->ToPlayer())
6456 {
6458 if (Battleground* bg = player->GetBattleground())
6459 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6460
6461 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6462 if (gain)
6463 player->UpdateCriteria(CriteriaType::HealingDone, gain, 0, 0, victim);
6464
6465 player->UpdateCriteria(CriteriaType::HighestHealCast, addhealth);
6466 }
6467 }
6468
6469 if (Player* player = victim->ToPlayer())
6470 {
6471 player->UpdateCriteria(CriteriaType::TotalHealReceived, gain);
6472 player->UpdateCriteria(CriteriaType::HighestHealReceived, addhealth);
6473 }
6474
6475 if (gain)
6476 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6477}
6478
6479bool Unit::IsMagnet() const
6480{
6481 // Grounding Totem
6482 if (*m_unitData->CreatedBySpell == 8177)
6483 return true;
6484
6485 return false;
6486}
6487
6488Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo /*= nullptr*/)
6489{
6491 for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i)
6492 {
6493 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6494 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6495 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6496 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6497 {
6498 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6499 return magnet;
6500 }
6501 }
6502 return victim;
6503}
6504
6506{
6507 // Sequence: charmed, pet, other guardians
6508 Unit* unit = GetCharmed();
6509 if (!unit)
6510 {
6511 ObjectGuid guid = GetMinionGUID();
6512 if (!guid.IsEmpty())
6513 unit = ObjectAccessor::GetUnit(*this, guid);
6514 }
6515
6516 return unit;
6517}
6518
6520{
6521 // possessed pet and vehicle
6522 if (GetTypeId() == TYPEID_PLAYER)
6524
6525 while (!m_Controlled.empty())
6526 {
6527 Unit* target = *m_Controlled.begin();
6528 m_Controlled.erase(m_Controlled.begin());
6529 if (target->GetCharmerGUID() == GetGUID())
6530 target->RemoveCharmAuras();
6531 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6532 target->ToTempSummon()->UnSummon();
6533 else
6534 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6535 }
6536 if (!GetPetGUID().IsEmpty())
6537 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6538 if (!GetMinionGUID().IsEmpty())
6539 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6540 if (!GetCharmedGUID().IsEmpty())
6541 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6542 if (!IsPet()) // pets don't use the flag for this
6543 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6544}
6545
6547{
6549}
6550
6552{
6553 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6554}
6555
6557{
6558 if (Unit* u = GetCharmed())
6559 return u->isPossessed();
6560 else
6561 return false;
6562}
6563
6565{
6566 Player* player = nullptr;
6567 if (GetTypeId() == TYPEID_PLAYER)
6568 player = ToPlayer();
6569 // Should we enable this also for charmed units?
6570 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6571 player = GetOwner()->ToPlayer();
6572
6573 if (!player)
6574 return nullptr;
6575 Group* group = player->GetGroup();
6576 // When there is no group check pet presence
6577 if (!group)
6578 {
6579 // We are pet now, return owner
6580 if (player != this)
6581 return IsWithinDistInMap(player, radius) ? player : nullptr;
6582 Unit* pet = GetGuardianPet();
6583 // No pet, no group, nothing to return
6584 if (!pet)
6585 return nullptr;
6586 // We are owner now, return pet
6587 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6588 }
6589
6590 std::vector<Unit*> nearMembers;
6591 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6592 nearMembers.reserve(group->GetMembersCount() * 2);
6593
6594 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
6595 if (Player* Target = itr->GetSource())
6596 {
6597 // IsHostileTo check duel and controlled by enemy
6598 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6599 nearMembers.push_back(Target);
6600
6601 // Push player's pet to vector
6602 if (Unit* pet = Target->GetGuardianPet())
6603 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6604 nearMembers.push_back(pet);
6605 }
6606
6607 if (nearMembers.empty())
6608 return nullptr;
6609
6610 uint32 randTarget = urand(0, nearMembers.size()-1);
6611 return nearMembers[randTarget];
6612}
6613
6614// only called in Player::SetSeer
6615// so move it to Player?
6617{
6618 if (m_sharedVision.empty())
6619 {
6620 setActive(true);
6622 }
6623 m_sharedVision.push_back(player);
6624}
6625
6626// only called in Player::SetSeer
6628{
6629 m_sharedVision.remove(player);
6630 if (m_sharedVision.empty())
6631 {
6632 setActive(false);
6634 }
6635}
6636
6638{
6640}
6641
6643{
6648}
6649
6651{
6652 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6653 {
6654 if (!m_SummonSlot[i])
6655 continue;
6656
6657 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6658 if (OldTotem->IsSummon())
6659 OldTotem->ToTempSummon()->UnSummon();
6660 }
6661}
6662
6663void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6664{
6666
6667 TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: {} Caster: {} Target: {} (Health: {} OverHeal: {} Absorbed: {} Crit: {})", healInfo.GetSpellInfo()->Id, healInfo.GetHealer()->GetGUID().ToString(), healInfo.GetTarget()->GetGUID().ToString(),
6668 healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), critical);
6669
6670 spellHealLog.TargetGUID = healInfo.GetTarget()->GetGUID();
6671 spellHealLog.CasterGUID = healInfo.GetHealer()->GetGUID();
6672 spellHealLog.SpellID = healInfo.GetSpellInfo()->Id;
6673 spellHealLog.Health = healInfo.GetHeal();
6674 spellHealLog.OriginalHeal = healInfo.GetOriginalHeal();
6675 spellHealLog.OverHeal = int32(healInfo.GetHeal()) - healInfo.GetEffectiveHeal();
6676 spellHealLog.Absorbed = healInfo.GetAbsorb();
6677 spellHealLog.Crit = critical;
6678 spellHealLog.LogData.Initialize(healInfo.GetTarget());
6679 SendCombatLogMessage(&spellHealLog);
6680}
6681
6682int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6683{
6684 // calculate heal absorb and reduce healing
6685 Unit::CalcHealAbsorb(healInfo);
6686 Unit::DealHeal(healInfo);
6687 SendHealSpellLog(healInfo, critical);
6688 return healInfo.GetEffectiveHeal();
6689}
6690
6691void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype)
6692{
6694 data.CasterGUID = GetGUID();
6695 data.TargetGUID = victim->GetGUID();
6696 data.SpellID = spellID;
6697 data.Type = powertype;
6698 data.Amount = damage;
6699 data.OverEnergize = overEnergize;
6700 data.LogData.Initialize(victim);
6701 SendCombatLogMessage(&data);
6702}
6703
6704void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6705{
6706 if (Player* player = victim->ToPlayer())
6707 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType))
6708 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UseRegenInterrupt))
6709 player->InterruptPowerRegen(powerType);
6710
6711 int32 gain = victim->ModifyPower(powerType, damage, false);
6712 int32 overEnergize = damage - gain;
6713 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage) / 2, spellInfo, true);
6714 SendEnergizeSpellLog(victim, spellInfo->Id, gain, overEnergize, powerType);
6715}
6716
6717int32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) const
6718{
6719 if (!spellProto || !victim)
6720 return pdamage;
6721
6722 int32 DoneTotal = 0;
6723 float DoneTotalMod = 1.0f;
6724
6725 auto callDamageScript = [&](int32& dmg, int32& flatMod, float& pctMod)
6726 {
6727 if (spell)
6728 spell->CallScriptCalcDamageHandlers(spellEffectInfo, victim, dmg, flatMod, pctMod);
6729 else if (aurEff)
6730 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, dmg, flatMod, pctMod);
6731 };
6732
6733 // Some spells don't benefit from done mods
6734 if (damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
6735 {
6736 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6737 return int32(std::max(float(pdamage + DoneTotal) * DoneTotalMod, 0.0f));
6738 }
6739
6740 // For totems get damage bonus from owner
6741 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6742 if (Unit* owner = GetOwner())
6743 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
6744
6745 DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6746
6747 // Done fixed damage bonus auras
6748 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6749 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6750 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6751
6752 // Pets just add their bonus damage to their spell damage
6753 // note that their spell damage is just gain of their own auras
6755 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6756
6757 // Check for table values
6758 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
6759 {
6760 float ApCoeffMod = spellEffectInfo.BonusCoefficientFromAP;
6761 if (Player* modOwner = GetSpellModOwner())
6762 {
6763 ApCoeffMod *= 100.0f;
6764 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, ApCoeffMod);
6765 ApCoeffMod /= 100.0f;
6766 }
6767
6768 WeaponAttackType const attType = [&]()
6769 {
6770 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
6771 return RANGED_ATTACK;
6772
6774 return OFF_ATTACK;
6775
6776 return BASE_ATTACK;
6777 }();
6779 APbonus += GetTotalAttackPowerValue(attType);
6780 DoneTotal += int32(stack * ApCoeffMod * APbonus);
6781 }
6782
6783 // Default calculation
6784 if (DoneAdvertisedBenefit)
6785 {
6786 float coeff = spellEffectInfo.BonusCoefficient;
6787 if (Player* modOwner = GetSpellModOwner())
6788 {
6789 coeff *= 100.0f;
6790 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
6791 coeff /= 100.0f;
6792 }
6793
6794 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
6795 }
6796
6797 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6798
6799 float tmpDamage = float(pdamage + DoneTotal) * DoneTotalMod;
6800
6801 // apply spellmod to Done damage (flat and pct)
6802 if (Player* modOwner = GetSpellModOwner())
6803 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage);
6804
6805 return int32(std::max(tmpDamage, 0.0f));
6806}
6807
6808float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const
6809{
6810 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6811 return 1.0f;
6812
6813 // Some spells don't benefit from done mods
6815 return 1.0f;
6816
6817 // Some spells don't benefit from pct done mods
6819 return 1.0f;
6820
6821 // For totems get damage bonus from owner
6822 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6823 if (Unit* owner = GetOwner())
6824 return owner->SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6825
6826 // Done total percent damage auras
6827 float DoneTotalMod = 1.0f;
6828
6829 // Pet damage?
6830 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6831 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->Classification);
6832
6833 // Versatility
6834 if (Player* modOwner = GetSpellModOwner())
6835 AddPct(DoneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
6836
6837 float maxModDamagePercentSchool = 0.0f;
6838 if (Player const* thisPlayer = ToPlayer())
6839 {
6840 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6841 if (spellProto->GetSchoolMask() & (1 << i))
6842 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
6843 }
6844 else
6845 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6846
6847 DoneTotalMod *= maxModDamagePercentSchool;
6848
6849 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6850
6852
6853 // bonus against aurastate
6854 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6855 {
6856 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6857 return true;
6858 return false;
6859 });
6860
6861 // bonus against target aura mechanic
6863 {
6864 if (victim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
6865 return true;
6866 return false;
6867 });
6868
6869 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6870 if (spellEffectInfo.Mechanic)
6872 else if (spellProto->Mechanic)
6874
6875 // Custom scripted damage
6876 switch (spellProto->SpellFamilyName)
6877 {
6878 case SPELLFAMILY_MAGE:
6879 // Ice Lance (no unique family flag)
6880 if (spellProto->Id == 228598)
6881 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6882 DoneTotalMod *= 3.0f;
6883 break;
6885 // Shadow Bite (30% increase from each dot)
6886 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
6887 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
6888 AddPct(DoneTotalMod, 30 * count);
6889
6890 // Drain Soul - increased damage for targets under 20% HP
6891 if (spellProto->Id == 198590)
6893 DoneTotalMod *= 2;
6894 break;
6895 }
6896
6897 return DoneTotalMod;
6898}
6899
6900int32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const
6901{
6902 if (!spellProto || damagetype == DIRECT_DAMAGE)
6903 return pdamage;
6904
6905 float TakenTotalMod = 1.0f;
6906
6907 // Mod damage from spell mechanic
6908 if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
6909 {
6910 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
6911 {
6912 if (mechanicMask & uint64(UI64LIT(1) << aurEff->GetMiscValue()))
6913 return true;
6914 return false;
6915 });
6916 }
6917
6918 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
6919 if (cheatDeath->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
6920 AddPct(TakenTotalMod, cheatDeath->GetAmount());
6921
6922 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
6924 {
6925 // Versatility
6926 if (Player* modOwner = GetSpellModOwner())
6927 {
6928 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
6929 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
6930 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
6931 }
6932
6933 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
6934 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
6936
6937 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_TAKEN_BY_LABEL, [spellProto](AuraEffect const* aurEff) -> bool
6938 {
6939 return spellProto->HasLabel(aurEff->GetMiscValue());
6940 });
6941
6942 // From caster spells
6943 if (caster)
6944 {
6945 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6946 {
6947 return aurEff->GetCasterGUID() == caster->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
6948 });
6949
6950 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6951 {
6952 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto);
6953 });
6954
6955 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER_BY_LABEL, [caster, spellProto](AuraEffect const* aurEff) -> bool
6956 {
6957 return aurEff->GetCasterGUID() == caster->GetGUID() && spellProto->HasLabel(aurEff->GetMiscValue());
6958 });
6959 }
6960
6961 if (damagetype == DOT)
6962 {
6963 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
6964 {
6965 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
6966 });
6967 }
6968 }
6969
6970 // Sanctified Wrath (bypass damage reduction)
6971 if (caster && TakenTotalMod < 1.0f)
6972 {
6973 float damageReduction = 1.0f - TakenTotalMod;
6975 for (AuraEffect const* aurEff : casterIgnoreResist)
6976 {
6977 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
6978 continue;
6979
6980 AddPct(damageReduction, -aurEff->GetAmount());
6981 }
6982
6983 TakenTotalMod = 1.0f - damageReduction;
6984 }
6985
6986 float tmpDamage = pdamage * TakenTotalMod;
6987 return int32(std::max(tmpDamage, 0.0f));
6988}
6989
6991{
6992 if (Player const* thisPlayer = ToPlayer())
6993 {
6994 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
6995 if (overrideSP > 0.0f)
6996 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
6997 }
6998
6999 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
7000
7001 if (GetTypeId() == TYPEID_PLAYER)
7002 {
7003 // Base value
7004 DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7005
7006 // Check if we are ever using mana - PaperDollFrame.lua
7008 DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7009
7010 // Damage bonus from stats
7012 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
7013 {
7014 if ((aurEff->GetMiscValue() & schoolMask) != 0)
7015 {
7016 // stat used stored in miscValueB for this aura
7017 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
7018 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
7019 }
7020 }
7021
7022 }
7023
7024 return DoneAdvertisedBenefit;
7025}
7026
7027float Unit::SpellCritChanceDone(Spell* spell, AuraEffect const* aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7028{
7029 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7031 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
7032 return 0.0f;
7033
7034 // not critting spell
7035 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7036 return 0.0f;
7037
7038 float crit_chance = 0.0f;
7039 switch (spellInfo->DmgClass)
7040 {
7043 {
7044 auto getPhysicalCritChance = [&]
7045 {
7046 return GetUnitCriticalChanceDone(attackType);
7047 };
7048
7049 auto getMagicCritChance = [&]
7050 {
7051 if (Player const* thisPlayer = ToPlayer())
7052 return *thisPlayer->m_activePlayerData->SpellCritPercentage;
7053
7054 return m_baseSpellCritChance;
7055 };
7056
7057 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
7058 crit_chance = std::max(crit_chance, getPhysicalCritChance());
7059
7060 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
7061 crit_chance = std::max(crit_chance, getMagicCritChance());
7062 break;
7063 }
7066 {
7067 crit_chance += GetUnitCriticalChanceDone(attackType);
7068 break;
7069 }
7070 default:
7071 return 0.0f;
7072 }
7073 // percent done
7074 // only players use intelligence for critical chance computations
7075 if (Player* modOwner = GetSpellModOwner())
7076 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritChance, crit_chance);
7077
7078 return std::max(crit_chance, 0.0f);
7079}
7080
7081float Unit::SpellCritChanceTaken(Unit const* caster, Spell* spell, AuraEffect const* aurEff, SpellSchoolMask /*schoolMask*/, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7082{
7083 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7084 // not critting spell
7085 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7086 return 0.0f;
7087
7088 float crit_chance = doneChance;
7089 switch (spellInfo->DmgClass)
7090 {
7092 {
7093 // taken
7094 if (!spellInfo->IsPositive())
7095 {
7096 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7098 }
7099
7100 if (caster)
7101 {
7102 // scripted (increase crit chance ... against ... target by x%
7103 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7104 for (AuraEffect const* aurEff : mOverrideClassScript)
7105 {
7106 if (!aurEff->IsAffectingSpell(spellInfo))
7107 continue;
7108
7109 switch (aurEff->GetMiscValue())
7110 {
7111 case 911: // Shatter
7112 if (HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7113 {
7114 crit_chance *= 1.5f;
7115 if (AuraEffect const* eff = aurEff->GetBase()->GetEffect(EFFECT_1))
7116 crit_chance += eff->GetAmount();
7117 }
7118 break;
7119 default:
7120 break;
7121 }
7122 }
7123 // Custom crit by class
7124 switch (spellInfo->SpellFamilyName)
7125 {
7126 case SPELLFAMILY_ROGUE:
7127 // Shiv-applied poisons can't crit
7128 if (caster->FindCurrentSpellBySpellId(5938))
7129 crit_chance = 0.0f;
7130 break;
7131 }
7132
7133 // Spell crit suppression
7134 if (GetTypeId() == TYPEID_UNIT)
7135 {
7136 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7137 crit_chance -= levelDiff * 1.0f;
7138 }
7139 }
7140 break;
7141 }
7143
7145 if (caster)
7146 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7147 break;
7149 default:
7150 return 0.f;
7151 }
7152
7153 // for this types the bonus was already added in GetUnitCriticalChance, do not add twice
7154 if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
7155 {
7156 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7157 {
7158 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo);
7159 });
7160 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster](AuraEffect const* aurEff) -> bool
7161 {
7162 return aurEff->GetCasterGUID() == caster->GetGUID();
7163 });
7164 crit_chance += caster->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH, [this](AuraEffect const* aurEff)
7165 {
7166 return !HealthBelowPct(aurEff->GetMiscValueB());
7167 });
7168 if (TempSummon const* tempSummon = caster->ToTempSummon())
7169 {
7170 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
7171 {
7172 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
7173 });
7174 }
7175 }
7176
7177 // call script handlers
7178 if (spell)
7179 spell->CallScriptCalcCritChanceHandlers(this, crit_chance);
7180 else
7181 aurEff->GetBase()->CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(GetGUID()), this, crit_chance);
7182
7183 return std::max(crit_chance, 0.0f);
7184}
7185
7186/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7187{
7188 // Calculate critical bonus
7189 int32 crit_bonus = damage * 2;
7190 float crit_mod = 0.0f;
7191
7192 if (caster)
7193 {
7194 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7195
7196 if (crit_bonus != 0)
7197 AddPct(crit_bonus, crit_mod);
7198
7200 {
7201 return aurEff->GetCasterGUID() == caster->GetGUID();
7202 }));
7203
7204 crit_bonus -= damage;
7205
7206 // adds additional damage to critBonus (from talents)
7207 if (Player* modOwner = caster->GetSpellModOwner())
7208 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7209
7210 crit_bonus += damage;
7211 }
7212
7213 return crit_bonus;
7214}
7215
7216/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/)
7217{
7218 // Calculate critical bonus
7219 int32 crit_bonus = damage;
7220
7221 // adds additional damage to critBonus (from talents)
7222 if (caster)
7223 if (Player* modOwner = caster->GetSpellModOwner())
7224 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7225
7226 damage += crit_bonus;
7227
7228 if (caster)
7229 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7230
7231 return damage;
7232}
7233
7234int32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) const
7235{
7236 // For totems get healing bonus from owner (statue isn't totem in fact)
7237 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7238 if (Unit* owner = GetOwner())
7239 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack, spell, aurEff);
7240
7241 // No bonus healing for potion spells
7242 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7243 return healamount;
7244
7245 int32 DoneTotal = 0;
7246 float DoneTotalMod = SpellHealingPctDone(victim, spellProto);
7247
7248 // done scripted mod (take it from owner)
7249 Unit const* owner = GetOwner() ? GetOwner() : this;
7250 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7251 for (AuraEffect const* aurEff : mOverrideClassScript)
7252 {
7253 if (!aurEff->IsAffectingSpell(spellProto))
7254 continue;
7255
7256 switch (aurEff->GetMiscValue())
7257 {
7258 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
7259 DoneTotal += aurEff->GetAmount();
7260 break;
7261 default:
7262 break;
7263 }
7264 }
7265
7266 // Done fixed damage bonus auras
7267 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7268 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7269 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7270
7271 // Pets just add their bonus damage to their spell damage
7272 // note that their spell damage is just gain of their own auras
7274 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7275
7276 // Check for table values
7277 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7278 {
7279 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
7281 APbonus += GetTotalAttackPowerValue(attType);
7282
7283 DoneTotal += int32(spellEffectInfo.BonusCoefficientFromAP * stack * APbonus);
7284 }
7285
7286 // Default calculation
7287 if (DoneAdvertisedBenefit)
7288 {
7289 float coeff = spellEffectInfo.BonusCoefficient;
7290 if (Player* modOwner = GetSpellModOwner())
7291 {
7292 coeff *= 100.0f;
7293 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7294 coeff /= 100.0f;
7295 }
7296
7297 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
7298 }
7299
7300 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7301 {
7302 switch (otherSpellEffect.ApplyAuraName)
7303 {
7304 // Bonus healing does not apply to these spells
7307 DoneTotal = 0;
7308 break;
7309 default:
7310 break;
7311 }
7312 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7313 DoneTotal = 0;
7314 }
7315
7316 if (spell)
7317 spell->CallScriptCalcHealingHandlers(spellEffectInfo, victim, healamount, DoneTotal, DoneTotalMod);
7318 else if (aurEff)
7319 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, healamount, DoneTotal, DoneTotalMod);
7320
7321 float heal = float(healamount + DoneTotal) * DoneTotalMod;
7322
7323 // apply spellmod to Done amount
7324 if (Player* modOwner = GetSpellModOwner())
7325 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal);
7326
7327 return int32(std::max(heal, 0.0f));
7328}
7329
7330float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7331{
7332 // For totems get healing bonus from owner
7333 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7334 if (Unit* owner = GetOwner())
7335 return owner->SpellHealingPctDone(victim, spellProto);
7336
7337 // Some spells don't benefit from done mods
7339 return 1.0f;
7340
7341 // Some spells don't benefit from done mods
7343 return 1.0f;
7344
7345 // Some spells don't benefit from done mods
7347 return 1.0f;
7348
7349 // No bonus healing for potion spells
7350 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7351 return 1.0f;
7352
7353 float DoneTotalMod = 1.0f;
7354
7355 // Healing done percent
7356 if (Player const* thisPlayer = ToPlayer())
7357 {
7358 float maxModDamagePercentSchool = 0.0f;
7359 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
7360 if (spellProto->GetSchoolMask() & (1 << i))
7361 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModHealingDonePercent[i]);
7362
7363 DoneTotalMod *= maxModDamagePercentSchool;
7364 }
7365 else // SPELL_AURA_MOD_HEALING_DONE_PERCENT is included in m_activePlayerData->ModHealingDonePercent for players
7367
7368 // bonus against aurastate
7369 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7370 {
7371 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
7372 return true;
7373 return false;
7374 });
7375
7376 // bonus from missing health of target
7377 float healthPctDiff = 100.0f - victim->GetHealthPct();
7379 if (healingDonePctVsTargetHealth->IsAffectingSpell(spellProto))
7380 AddPct(DoneTotalMod, CalculatePct(float(healingDonePctVsTargetHealth->GetAmount()), healthPctDiff));
7381
7382 return DoneTotalMod;
7383}
7384
7385int32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const
7386{
7387 bool allowPositive = !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_HEALING_MODIFIERS);
7389 if (!allowPositive && !allowNegative)
7390 return healamount;
7391
7392 float TakenTotalMod = 1.0f;
7393
7394 // Healing taken percent
7395 if (allowNegative)
7396 {
7398 if (minval)
7399 AddPct(TakenTotalMod, minval);
7400
7401 if (damagetype == DOT)
7402 {
7403 // Healing over time taken percent
7404 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7405 if (minval_hot)
7406 AddPct(TakenTotalMod, minval_hot);
7407 }
7408 }
7409
7410 if (allowPositive)
7411 {
7413 if (maxval)
7414 AddPct(TakenTotalMod, maxval);
7415
7416 if (damagetype == DOT)
7417 {
7418 // Healing over time taken percent
7419 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7420 if (maxval_hot)
7421 AddPct(TakenTotalMod, maxval_hot);
7422 }
7423
7424 // Nourish cast
7425 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7426 {
7427 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7429 // increase healing by 20%
7430 TakenTotalMod *= 1.2f;
7431 }
7432 }
7433
7434 if (caster)
7435 {
7436 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7437 {
7438 if (caster->GetGUID() != aurEff->GetCasterGUID() || !aurEff->IsAffectingSpell(spellProto))
7439 return false;
7440
7441 if (aurEff->GetAmount() > 0)
7442 {
7443 if (!allowPositive)
7444 return false;
7445 }
7446 else if (!allowNegative)
7447 return false;
7448
7449 return true;
7450 });
7451
7452 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER, [caster, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7453 {
7454 if (aurEff->GetCasterGUID() != caster->GetGUID())
7455 return false;
7456
7457 if (aurEff->GetAmount() > 0)
7458 {
7459 if (!allowPositive)
7460 return false;
7461 }
7462 else if (!allowNegative)
7463 return false;
7464
7465 return true;
7466 });
7467 }
7468
7469 float heal = healamount * TakenTotalMod;
7470 return int32(std::max(heal, 0.0f));
7471}
7472
7474{
7475 if (Player const* thisPlayer = ToPlayer())
7476 {
7477 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7478 if (overrideSP > 0.0f)
7479 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7480 }
7481
7482 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7483 {
7484 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7485 return true;
7486 return false;
7487 });
7488
7489 // Healing bonus of spirit, intellect and strength
7490 if (GetTypeId() == TYPEID_PLAYER)
7491 {
7492 // Base value
7493 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7494
7495 // Check if we are ever using mana - PaperDollFrame.lua
7497 advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7498
7499 // Healing bonus from stats
7501 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7502 {
7503 // stat used dependent from misc value (stat index)
7504 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7505 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7506 }
7507 }
7508 return advertisedBenefit;
7509}
7510
7511bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7512{
7513 if (!spellInfo)
7514 return false;
7515
7516 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7517 {
7519 if (!requireImmunityPurgesEffectAttribute)
7520 return range.begin() != range.end();
7521
7522 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7523 {
7524 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
7525 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7526 return true;
7527
7528 return false;
7529 });
7530 };
7531
7532 // Single spell immunity.
7534 if (hasImmunity(idList, spellInfo->Id))
7535 return true;
7536
7538 return false;
7539
7540 if (uint32 dispel = spellInfo->Dispel)
7541 {
7543 if (hasImmunity(dispelList, dispel))
7544 return true;
7545 }
7546
7547 // Spells that don't have effectMechanics.
7548 if (uint32 mechanic = spellInfo->Mechanic)
7549 {
7551 if (hasImmunity(mechanicList, mechanic))
7552 return true;
7553 }
7554
7555 bool immuneToAllEffects = true;
7556 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7557 {
7558 // State/effect immunities applied by aura expect full spell immunity
7559 // Ignore effects with mechanic, they are supposed to be checked separately
7560 if (!spellEffectInfo.IsEffect())
7561 continue;
7562 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7563 {
7564 immuneToAllEffects = false;
7565 break;
7566 }
7568 return true;
7569 }
7570
7571 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7572 return true;
7573
7574 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7575 {
7576 uint32 schoolImmunityMask = 0;
7578 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7579 {
7580 if ((itr->first & schoolMask) == 0)
7581 continue;
7582
7583 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID());
7584 if (requireImmunityPurgesEffectAttribute)
7585 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7586 continue;
7587
7588 if (!(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)) && caster && caster->IsFriendlyTo(this))
7589 continue;
7590
7591 if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7592 continue;
7593
7594 schoolImmunityMask |= itr->first;
7595 }
7596 if ((schoolImmunityMask & schoolMask) == schoolMask)
7597 return true;
7598 }
7599
7600 return false;
7601}
7602
7604{
7605 uint32 mask = 0;
7607 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7608 mask |= itr->first;
7609
7610 return mask;
7611}
7612
7614{
7615 uint32 mask = 0;
7617 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7618 mask |= itr->first;
7619
7620 return mask;
7621}
7622
7624{
7625 uint64 mask = 0;
7627 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7628 mask |= (UI64LIT(1) << itr->first);
7629
7630 return mask;
7631}
7632
7634{
7635 SpellOtherImmunity mask = { };
7637 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7638 mask |= SpellOtherImmunity(itr->first);
7639
7640 return mask;
7641}
7642
7644{
7645 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7646 return false;
7647
7648 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7649 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7650 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7651 return true;
7652
7653 // If m_immuneToDamage type contain magic, IMMUNE damage.
7654 uint32 damageImmunityMask = GetDamageImmunityMask();
7655 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7656 return true;
7657
7658 return false;
7659}
7660
7661bool Unit::IsImmunedToDamage(WorldObject const* caster, SpellInfo const* spellInfo, SpellEffectInfo const* spellEffectInfo /*= nullptr*/) const
7662{
7663 if (!spellInfo)
7664 return false;
7665
7667 return false;
7668
7669 if (spellEffectInfo && spellEffectInfo->EffectAttributes.HasFlag(SpellEffectAttributes::NoImmunity))
7670 return false;
7671
7672 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7673 {
7674 auto hasImmunity = [&](SpellImmuneContainer const& container)
7675 {
7676 uint32 schoolImmunityMask = 0;
7677 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
7678 {
7679 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7680 if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
7681 continue;
7682
7683 if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
7684 continue;
7685
7686 schoolImmunityMask |= immunitySchoolMask;
7687 }
7688
7689 // // We need to be immune to all types
7690 return (schoolImmunityMask & schoolMask) == schoolMask;
7691 };
7692
7693 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7694 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
7695 return true;
7696
7697 // If m_immuneToDamage type contain magic, IMMUNE damage.
7698 if (hasImmunity(m_spellImmune[IMMUNITY_DAMAGE]))
7699 return true;
7700 }
7701
7702 return false;
7703}
7704
7705bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
7706 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7707{
7708 if (!spellInfo)
7709 return false;
7710
7712 return false;
7713
7715 return false;
7716
7717 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7718 {
7720 if (!requireImmunityPurgesEffectAttribute)
7721 return range.begin() != range.end();
7722
7723 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7724 {
7725 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
7726 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7727 return true;
7728
7729 return false;
7730 });
7731 };
7732
7733 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7734 auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
7735 if (hasImmunity(effectList, spellEffectInfo.Effect))
7736 return true;
7737
7738 if (uint32 mechanic = spellEffectInfo.Mechanic)
7739 {
7741 if (hasImmunity(mechanicList, mechanic))
7742 return true;
7743 }
7744
7745 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7746 {
7747 if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
7748 {
7750 if (hasImmunity(list, aura))
7751 return true;
7752 }
7753
7755 {
7756 // Check for immune to application of harmful magical effects
7758 {
7759 if (!(immuneAuraApply->GetMiscValue() & spellInfo->GetSchoolMask())) // Check school
7760 continue;
7761
7762 if (immuneAuraApply->GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || (caster && !IsFriendlyTo(caster))) // Harmful
7763 return true;
7764 }
7765 }
7766 }
7767
7768 return false;
7769}
7770
7771bool Unit::IsImmunedToAuraPeriodicTick(WorldObject const* caster, SpellInfo const* spellInfo, SpellEffectInfo const* spellEffectInfo) const
7772{
7773 if (!spellInfo)
7774 return false;
7775
7776 if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) /*only school immunities are checked in this function*/)
7777 return false;
7778
7779 if (spellEffectInfo && spellEffectInfo->EffectAttributes.HasFlag(SpellEffectAttributes::NoImmunity))
7780 return false;
7781
7782 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7783 {
7784 auto hasImmunity = [&](SpellImmuneContainer const& container)
7785 {
7786 uint32 schoolImmunityMask = 0;
7787 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
7788 {
7789 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7790 if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
7791 continue;
7792
7793 schoolImmunityMask |= immunitySchoolMask;
7794 }
7795
7796 // // We need to be immune to all types
7797 return (schoolImmunityMask & schoolMask) == schoolMask;
7798 };
7799
7800 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7801 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
7802 return true;
7803 }
7804
7805 return false;
7806}
7807
7808int32 Unit::MeleeDamageBonusDone(Unit* pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellEffectInfo const* spellEffectInfo /*= nullptr*/, Mechanics mechanic /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/)
7809{
7810 if (!pVictim || damage == 0)
7811 return 0;
7812
7813 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7814
7815 // Done fixed damage bonus auras
7816 int32 DoneFlatBenefit = 0;
7817
7818 // ..done
7819 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
7820
7821 // ..done
7822 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
7823
7824 // ..done (base at attack power for marked target and base at attack power for creature type)
7825 int32 APbonus = 0;
7826
7827 if (attType == RANGED_ATTACK)
7828 {
7830
7831 // ..done (base at attack power and creature type)
7833 }
7834 else
7835 {
7837
7838 // ..done (base at attack power and creature type)
7840 }
7841
7842 if (APbonus != 0) // Can be negative
7843 {
7844 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
7845 DoneFlatBenefit += int32(APbonus / 3.5f * GetAPMultiplier(attType, normalized));
7846 }
7847
7848 // Done total percent damage auras
7849 float DoneTotalMod = 1.0f;
7850
7851 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
7852
7853 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
7854 {
7855 // Some spells don't benefit from pct done mods
7856 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
7857 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS))
7858 {
7859 float maxModDamagePercentSchool = 0.0f;
7860 if (Player const* thisPlayer = ToPlayer())
7861 {
7862 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
7863 if (schoolMask & (1 << i))
7864 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
7865 }
7866 else
7867 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
7868
7869 DoneTotalMod *= maxModDamagePercentSchool;
7870 }
7871 }
7872
7873 if (!spellProto)
7874 {
7875 // melee attack
7877 AddPct(DoneTotalMod, autoAttackDamage->GetAmount());
7878 }
7879
7881
7882 // bonus against aurastate
7883 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [pVictim](AuraEffect const* aurEff) -> bool
7884 {
7885 if (pVictim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
7886 return true;
7887 return false;
7888 });
7889
7890 // bonus against target aura mechanic
7892 {
7893 if (pVictim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
7894 return true;
7895 return false;
7896 });
7897
7898 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
7899 if (mechanic != MECHANIC_NONE)
7901 else if (spellProto && spellProto->Mechanic)
7903
7904 if (spell)
7905 spell->CallScriptCalcDamageHandlers(*spellEffectInfo, pVictim, damage, DoneFlatBenefit, DoneTotalMod);
7906 else if (aurEff)
7907 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID()), pVictim, damage, DoneFlatBenefit, DoneTotalMod);
7908
7909 float damageF = float(damage + DoneFlatBenefit) * DoneTotalMod;
7910
7911 // apply spellmod to Done damage
7912 if (spellProto)
7913 if (Player* modOwner = GetSpellModOwner())
7914 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF);
7915
7916 // bonus result can be negative
7917 return int32(std::max(damageF, 0.0f));
7918}
7919
7920int32 Unit::MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
7921{
7922 if (pdamage == 0)
7923 return 0;
7924
7925 int32 TakenFlatBenefit = 0;
7926
7927 // ..taken
7929
7930 if (attType != RANGED_ATTACK)
7932 else
7934
7935 if ((TakenFlatBenefit < 0) && (pdamage < -TakenFlatBenefit))
7936 return 0;
7937
7938 // Taken total percent damage auras
7939 float TakenTotalMod = 1.0f;
7940
7941 // ..taken
7943
7944 // .. taken pct (special attacks)
7945 if (spellProto)
7946 {
7947 // From caster spells
7948 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
7949 {
7950 return aurEff->GetCasterGUID() == attacker->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
7951 });
7952
7953 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
7954 {
7955 return aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto);
7956 });
7957
7958 // Mod damage from spell mechanic
7959 uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
7960
7961 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
7962 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
7963 mechanicMask |= (1 << MECHANIC_BLEED);
7964
7965 if (mechanicMask)
7966 {
7967 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
7968 {
7969 if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
7970 return true;
7971 return false;
7972 });
7973 }
7974
7975 if (damagetype == DOT)
7976 {
7977 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
7978 {
7979 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
7980 });
7981 }
7982 }
7983 else // melee attack
7984 {
7985 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER, [attacker](AuraEffect const* aurEff) -> bool
7986 {
7987 return aurEff->GetCasterGUID() == attacker->GetGUID();
7988 });
7989 }
7990
7991 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
7992 AddPct(TakenTotalMod, cheatDeath->GetAmount());
7993
7994 if (attType != RANGED_ATTACK)
7996 else
7998
7999 // Versatility
8000 if (Player* modOwner = GetSpellModOwner())
8001 {
8002 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
8003 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
8004 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
8005 }
8006
8007 // Sanctified Wrath (bypass damage reduction)
8008 if (TakenTotalMod < 1.0f)
8009 {
8010 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8011
8012 float damageReduction = 1.0f - TakenTotalMod;
8014 for (AuraEffect const* aurEff : casterIgnoreResist)
8015 {
8016 if (!(aurEff->GetMiscValue() & attackSchoolMask))
8017 continue;
8018
8019 AddPct(damageReduction, -aurEff->GetAmount());
8020 }
8021
8022 TakenTotalMod = 1.0f - damageReduction;
8023 }
8024
8025 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
8026 return int32(std::max(tmpDamage, 0.0f));
8027}
8028
8030{
8031 if (apply)
8032 m_spellImmune[op].emplace(type, spellId);
8033 else
8034 {
8035 auto bounds = m_spellImmune[op].equal_range(type);
8036 for (auto itr = bounds.first; itr != bounds.second;)
8037 {
8038 if (itr->second == spellId)
8039 itr = m_spellImmune[op].erase(itr);
8040 else
8041 ++itr;
8042 }
8043 }
8044}
8045
8047{
8048 // normalized proc chance for weapon attack speed
8049 // (odd formula...)
8051 return (GetBaseAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8053 return (GetBaseAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8054 return 0;
8055}
8056
8057float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
8058{
8059 // proc per minute chance calculation
8060 if (PPM <= 0)
8061 return 0.0f;
8062
8063 // Apply chance modifer aura
8064 if (spellProto)
8065 if (Player* modOwner = GetSpellModOwner())
8066 modOwner->ApplySpellMod(spellProto, SpellModOp::ProcFrequency, PPM);
8067
8068 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8069}
8070
8071void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
8072{
8074 if (mount)
8075 SetMountDisplayId(mount);
8076
8078
8080
8081 if (Player* player = ToPlayer())
8082 {
8083 // mount as a vehicle
8084 if (VehicleId)
8085 {
8086 if (CreateVehicleKit(VehicleId, creatureEntry))
8087 {
8088 player->SendOnCancelExpectedVehicleRideAura();
8089
8090 // mounts can also have accessories
8092 }
8093 }
8094
8095 // disable pet controls
8096 player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
8097
8098 player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8099 }
8100
8102}
8103
8105{
8106 if (!IsMounted())
8107 return;
8108
8111
8112 if (Player* thisPlayer = ToPlayer())
8113 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8114
8116
8117 // dismount as a vehicle
8119 {
8120 // Remove vehicle from player
8122 }
8123
8125
8126 // only resummon old pet if the player is already added to a map
8127 // this prevents adding a pet to a not created map which would otherwise cause a crash
8128 // (it could probably happen when logging in after a previous crash)
8129 if (Player* player = ToPlayer())
8130 {
8131 player->EnablePetControlsOnDismount();
8132 player->ResummonPetTemporaryUnSummonedIfAny();
8133 player->ResummonBattlePetTemporaryUnSummonedIfAny();
8134 }
8135}
8136
8138{
8140 return;
8141
8143 {
8144 SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
8145 return force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive());
8146 });
8147}
8148
8150{
8151 if (!mountType)
8152 return nullptr;
8153
8154 DB2Manager::MountTypeXCapabilitySet const* capabilities = sDB2Manager.GetMountCapabilities(mountType);
8155 if (!capabilities)
8156 return nullptr;
8157
8158 uint32 areaId = GetAreaId();
8159 uint32 ridingSkill = 5000;
8161 bool isSubmerged = false;
8162 bool isInWater = false;
8163
8164 if (GetTypeId() == TYPEID_PLAYER)
8165 ridingSkill = ToPlayer()->GetSkillValue(SKILL_RIDING);
8166
8168 {
8170 mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
8171 }
8172 else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(areaId))
8173 mountFlags = areaTable->GetMountFlags();
8174
8175 LiquidData liquid;
8176 ZLiquidStatus liquidStatus = GetMap()->GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), {}, &liquid);
8177 isSubmerged = (liquidStatus & LIQUID_MAP_UNDER_WATER) != 0 || HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
8178 isInWater = (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
8179
8180 for (MountTypeXCapabilityEntry const* mountTypeXCapability : *capabilities)
8181 {
8182 MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeXCapability->MountCapabilityID);
8183 if (!mountCapability)
8184 continue;
8185
8186 if (ridingSkill < mountCapability->ReqRidingSkill)
8187 continue;
8188
8189 if (!(mountCapability->Flags & MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS))
8190 {
8191 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND && !(mountFlags.HasFlag(AreaMountFlags::AllowGroundMounts)))
8192 continue;
8193 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
8194 continue;
8196 continue;
8198 continue;
8199 }
8200
8201 if (!isSubmerged)
8202 {
8203 if (!isInWater)
8204 {
8205 // player is completely out of water
8206 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND))
8207 continue;
8208 }
8209 // player is on water surface
8210 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8211 continue;
8212 }
8213 else if (isInWater)
8214 {
8215 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_UNDERWATER))
8216 continue;
8217 }
8218 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8219 continue;
8220
8221 if (mountCapability->ReqMapID != -1 &&
8222 int32(GetMapId()) != mountCapability->ReqMapID &&
8223 GetMap()->GetEntry()->CosmeticParentMapID != mountCapability->ReqMapID &&
8224 GetMap()->GetEntry()->ParentMapID != mountCapability->ReqMapID)
8225 continue;
8226
8227 if (mountCapability->ReqAreaID && !DB2Manager::IsInArea(areaId, mountCapability->ReqAreaID))
8228 continue;
8229
8230 if (mountCapability->ReqSpellAuraID && !HasAura(mountCapability->ReqSpellAuraID))
8231 continue;
8232
8233 if (mountCapability->ReqSpellKnownID && !HasSpell(mountCapability->ReqSpellKnownID))
8234 continue;
8235
8236 if (Player const* thisPlayer = ToPlayer())
8237 if (!ConditionMgr::IsPlayerMeetingCondition(thisPlayer, mountCapability->PlayerConditionID))
8238 continue;
8239
8240 return mountCapability;
8241 }
8242
8243 return nullptr;
8244}
8245
8247{
8248 if (IsLoading())
8249 return;
8250
8251 if (SpellShapeshiftFormEntry const* spellShapeshiftForm = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()))
8252 if (uint32 mountType = spellShapeshiftForm->MountTypeID)
8253 if (!GetMountCapability(mountType))
8255
8257 for (AuraEffect* aurEff : mounts)
8258 {
8259 aurEff->RecalculateAmount();
8260 if (!aurEff->GetAmount())
8261 aurEff->GetBase()->Remove();
8262 else if (MountCapabilityEntry const* capability = sMountCapabilityStore.LookupEntry(aurEff->GetAmount())) // aura may get removed by interrupt flag, reapply
8263 {
8264 SetFlightCapabilityID(capability->FlightCapabilityID, true);
8265
8266 if (!HasAura(capability->ModSpellAuraID))
8267 CastSpell(this, capability->ModSpellAuraID, aurEff);
8268 }
8269 }
8270}
8271
8273{
8274 return HasNpcFlag(
8279}
8280
8282{
8283 if (!enemy)
8284 return;
8285
8286 if (CanHaveThreatList())
8287 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8288 else
8289 SetInCombatWith(enemy);
8290}
8291
8292void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8293{
8294 if (apply)
8295 {
8298 if (!keepCombat)
8300 }
8301 else
8303}
8304
8305void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8306{
8307 if (apply)
8308 {
8311 if (!keepCombat)
8312 {
8313 std::list<CombatReference*> toEnd;
8314 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8315 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8316 toEnd.push_back(pair.second);
8317 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8318 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8319 toEnd.push_back(pair.second);
8320 for (CombatReference* ref : toEnd)
8321 ref->EndCombat();
8322 }
8323 }
8324 else
8326}
8327
8328void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8329{
8330 if (apply)
8331 {
8334 if (!keepCombat)
8335 {
8336 std::list<CombatReference*> toEnd;
8337 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8338 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8339 toEnd.push_back(pair.second);
8340 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8341 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8342 toEnd.push_back(pair.second);
8343 for (CombatReference* ref : toEnd)
8344 ref->EndCombat();
8345 }
8346 }
8347 else
8349}
8350
8352{
8353 if (apply)
8355 else
8357}
8358
8360{
8361 if (apply)
8363 else
8365}
8366
8368{
8370}
8371
8372bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8373{
8374 if (!IsAlive())
8375 return false;
8376
8378 return false;
8379
8380 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8381 return false;
8382
8383 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8384}
8385
8387{
8388 int64 gain = 0;
8389
8390 if (dVal == 0)
8391 return 0;
8392
8393 int64 curHealth = (int64)GetHealth();
8394
8395 int64 val = dVal + curHealth;
8396 if (val <= 0)
8397 {
8398 SetHealth(0);
8399 return -curHealth;
8400 }
8401
8402 int64 maxHealth = (int64)GetMaxHealth();
8403
8404 if (val < maxHealth)
8405 {
8406 SetHealth(val);
8407 gain = val - curHealth;
8408 }
8409 else if (curHealth != maxHealth)
8410 {
8411 SetHealth(maxHealth);
8412 gain = maxHealth - curHealth;
8413 }
8414
8415 if (dVal < 0)
8416 {
8418 packet.Guid = GetGUID();
8419 packet.Health = GetHealth();
8420
8422 player->GetSession()->SendPacket(packet.Write());
8423 }
8424
8425 return gain;
8426}
8427
8429{
8430 int64 gain = 0;
8431
8432 if (dVal == 0)
8433 return 0;
8434
8435 int64 curHealth = (int64)GetHealth();
8436
8437 int64 val = dVal + curHealth;
8438 if (val <= 0)
8439 {
8440 return -curHealth;
8441 }
8442
8443 int64 maxHealth = (int64)GetMaxHealth();
8444
8445 if (val < maxHealth)
8446 gain = dVal;
8447 else if (curHealth != maxHealth)
8448 gain = maxHealth - curHealth;
8449
8450 return gain;
8451}
8452
8454{
8456 return;
8457
8459 for (AuraEffect const* effect : effects)
8460 {
8461 uint32 triggerHealthPct = effect->GetAmount();
8462 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
8463 uint64 threshold = CountPctFromMaxHealth(triggerHealthPct);
8464
8465 switch (AuraTriggerOnHealthChangeDirection(effect->GetMiscValue()))
8466 {
8468 if (newVal < threshold || oldVal > threshold)
8469 continue;
8470 break;
8472 if (newVal > threshold || oldVal < threshold)
8473 continue;
8474 break;
8475 default:
8476 break;
8477 }
8478
8479 CastSpell(this, triggerSpell, effect);
8480 }
8481}
8482
8483// returns negative amount on power reduction
8484int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8485{
8486 int32 gain = 0;
8487
8488 if (dVal == 0)
8489 return 0;
8490
8491 if (dVal > 0)
8493
8494 int32 curPower = GetPower(power);
8495
8496 int32 val = dVal + curPower;
8497 if (val <= GetMinPower(power))
8498 {
8499 SetPower(power, GetMinPower(power), withPowerUpdate);
8500 return -curPower;
8501 }
8502
8503 int32 maxPower = GetMaxPower(power);
8504
8505 if (val < maxPower)
8506 {
8507 SetPower(power, val, withPowerUpdate);
8508 gain = val - curPower;
8509 }
8510 else if (curPower != maxPower)
8511 {
8512 SetPower(power, maxPower, withPowerUpdate);
8513 gain = maxPower - curPower;
8514 }
8515
8516 return gain;
8517}
8518
8520{
8522 return true;
8523
8524 // Always seen by owner
8526 if (!guid.IsEmpty())
8527 if (seer->GetGUID() == guid)
8528 return true;
8529
8530 if (Player const* seerPlayer = seer->ToPlayer())
8531 if (Unit* owner = GetOwner())
8532 if (Player* ownerPlayer = owner->ToPlayer())
8533 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8534 return true;
8535
8536 return false;
8537}
8538
8540{
8542 return true;
8543
8545 return true;
8546
8547 return false;
8548}
8549
8551{
8553}
8554
8556{
8557 if (!x)
8559 else
8561
8563}
8564
8566{
8567 int32 main_speed_mod = 0;
8568 float stack_bonus = 1.0f;
8569 float non_stack_bonus = 1.0f;
8570
8571 switch (mtype)
8572 {
8573 // Only apply debuffs
8574 case MOVE_FLIGHT_BACK:
8575 case MOVE_RUN_BACK:
8576 case MOVE_SWIM_BACK:
8577 break;
8578 case MOVE_WALK:
8579 return;
8580 case MOVE_RUN:
8581 {
8582 if (IsMounted()) // Use on mount auras
8583 {
8587 }
8588 else
8589 {
8593 }
8594 break;
8595 }
8596 case MOVE_SWIM:
8597 {
8599 break;
8600 }
8601 case MOVE_FLIGHT:
8602 {
8603 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8604 {
8607
8608 // for some spells this mod is applied on vehicle owner
8609 int32 owner_speed_mod = 0;
8610
8611 if (Unit* owner = GetCharmer())
8612 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8613
8614 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8615 }
8616 else if (IsMounted())
8617 {
8620 }
8621 else // Use not mount (shapeshift for example) auras (should stack)
8623
8625
8626 // Update speed for vehicle if available
8627 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8629 break;
8630 }
8631 default:
8632 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8633 return;
8634 }
8635
8636 // now we ready for speed calculation
8637 float speed = std::max(non_stack_bonus, stack_bonus);
8638 if (main_speed_mod)
8639 AddPct(speed, main_speed_mod);
8640
8641 switch (mtype)
8642 {
8643 case MOVE_RUN:
8644 case MOVE_SWIM:
8645 case MOVE_FLIGHT:
8646 {
8647 // Set creature speed rate
8648 if (GetTypeId() == TYPEID_UNIT)
8649 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8650
8651 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8654 {
8655 if (Creature* creature = ToCreature())
8656 if (CreatureImmunities const* immunities = SpellMgr::GetCreatureImmunities(creature->GetCreatureTemplate()->CreatureImmunitiesId))
8657 if (immunities->Mechanic[MECHANIC_SNARE] || immunities->Mechanic[MECHANIC_DAZE])
8658 break;
8659
8660 // Use speed from aura
8661 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8662 if (speed > max_speed)
8663 speed = max_speed;
8664 }
8665
8666 if (mtype == MOVE_RUN)
8667 {
8668 // force minimum speed rate @ aura 437 SPELL_AURA_MOD_MINIMUM_SPEED_RATE
8670 {
8671 float minSpeed = minSpeedMod / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8672 if (speed < minSpeed)
8673 speed = minSpeed;
8674 }
8675 }
8676 break;
8677 }
8678 default:
8679 break;
8680 }
8681
8682 if (Creature* creature = ToCreature())
8683 {
8684 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8685 {
8687 {
8688 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8689 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8690 {
8691 float ownerSpeed = followed->GetSpeedRate(mtype);
8692 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8693 speed = ownerSpeed;
8694 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8695 }
8696 }
8697 }
8698 }
8699
8700 // Apply strongest slow aura mod to speed
8702 if (slow)
8703 AddPct(speed, slow);
8704
8705 if (float minSpeedMod = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED))
8706 {
8707 float baseMinSpeed = 1.0f;
8708 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8709 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8710
8711 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8712 if (speed < min_speed)
8713 speed = min_speed;
8714 }
8715
8716 SetSpeedRate(mtype, speed);
8717}
8718
8720{
8721 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8722}
8723
8724void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8725{
8726 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8727}
8728
8729void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8730{
8731 rate = std::max(rate, 0.01f);
8732
8733 // Update speed only on change
8734 if (m_speed_rate[mtype] == rate)
8735 return;
8736
8737 m_speed_rate[mtype] = rate;
8738
8740
8741 // Spline packets are for creatures and move_update are for players
8742 static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
8743 {
8753 };
8754
8755 if (GetTypeId() == TYPEID_PLAYER)
8756 {
8757 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8758 // and do it only for real sent packets and use run for run/mounted as client expected
8759 ++ToPlayer()->m_forced_speed_changes[mtype];
8760
8761 if (!IsInCombat())
8762 if (Pet* pet = ToPlayer()->GetPet())
8763 pet->SetSpeedRate(mtype, m_speed_rate[mtype]);
8764 }
8765
8766 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
8767 {
8768 // Send notification to self
8769 WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]);
8770 selfpacket.MoverGUID = GetGUID();
8771 selfpacket.SequenceIndex = m_movementCounter++;
8772 selfpacket.Speed = GetSpeed(mtype);
8773 playerMover->GetSession()->SendPacket(selfpacket.Write());
8774
8775 // Send notification to other players
8776 WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]);
8777 packet.Status = &m_movementInfo;
8778 packet.Speed = GetSpeed(mtype);
8779 playerMover->SendMessageToSet(packet.Write(), false);
8780 }
8781 else
8782 {
8783 WorldPackets::Movement::MoveSplineSetSpeed packet(moveTypeToOpcode[mtype][0]);
8784 packet.MoverGUID = GetGUID();
8785 packet.Speed = GetSpeed(mtype);
8786 SendMessageToSet(packet.Write(), true);
8787 }
8788}
8789
8790void Unit::SetFlightCapabilityID(int32 flightCapabilityId, bool clientUpdate)
8791{
8792 if (flightCapabilityId && !sFlightCapabilityStore.HasRecord(flightCapabilityId))
8793 return;
8794
8796
8810}
8811
8812void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
8813{
8814 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
8815 if (!flightCapabilityEntry)
8816 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
8817
8818 auto [opcode, newValue, rateAura] = [&]
8819 {
8820 switch (speedType)
8821 {
8824 case ADV_FLYING_MAX_VEL:
8825 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_MAX_VEL, flightCapabilityEntry->MaxVel, SPELL_AURA_MOD_ADV_FLYING_MAX_VEL);
8829 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD, flightCapabilityEntry->DoubleJumpVelMod, SPELL_AURA_NONE);
8835 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION, flightCapabilityEntry->SurfaceFriction, SPELL_AURA_NONE);
8840 default:
8841 return std::tuple<OpcodeServer, float, AuraType>();
8842 }
8843 }();
8844
8845 if (rateAura != SPELL_AURA_NONE)
8846 {
8847 // take only lowest negative and highest positive auras - these effects do not stack
8848 if (int32 neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
8849 ApplyPct(newValue, neg);
8850
8851 if (int32 pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
8852 ApplyPct(newValue, pos);
8853 }
8854
8855 if (m_advFlyingSpeed[speedType] == newValue)
8856 return;
8857
8858 m_advFlyingSpeed[speedType] = newValue;
8859
8860 if (!clientUpdate)
8861 return;
8862
8863 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
8864 {
8866 selfpacket.MoverGUID = GetGUID();
8867 selfpacket.SequenceIndex = m_movementCounter++;
8868 selfpacket.Speed = newValue;
8869 playerMover->GetSession()->SendPacket(selfpacket.Write());
8870 }
8871}
8872
8873void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeRange speedType, bool clientUpdate)
8874{
8875 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
8876 if (!flightCapabilityEntry)
8877 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
8878
8879 auto [opcode, min, max, rateAura] = [&]
8880 {
8881 switch (speedType)
8882 {
8884 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE, flightCapabilityEntry->BankingRateMin, flightCapabilityEntry->BankingRateMax, SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE);
8888 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP, flightCapabilityEntry->PitchingRateUpMin, flightCapabilityEntry->PitchingRateUpMax, SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP);
8890 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD, flightCapabilityEntry->TurnVelocityThresholdMin, flightCapabilityEntry->TurnVelocityThresholdMax, SPELL_AURA_NONE);
8891 default:
8892 return std::tuple<OpcodeServer, float, float, AuraType>();
8893 }
8894 }();
8895
8896 if (rateAura != SPELL_AURA_NONE)
8897 {
8898 // take only lowest negative and highest positive auras - these effects do not stack
8899 if (int32 neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
8900 {
8901 ApplyPct(min, neg);
8902 ApplyPct(max, neg);
8903 }
8904
8905 if (int32 pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
8906 {
8907 ApplyPct(min, pos);
8908 ApplyPct(max, pos);
8909 }
8910 }
8911
8912 if (m_advFlyingSpeed[speedType] == min && m_advFlyingSpeed[speedType + 1] == max)
8913 return;
8914
8915 m_advFlyingSpeed[speedType] = min;
8916 m_advFlyingSpeed[speedType + 1] = max;
8917
8918 if (!clientUpdate)
8919 return;
8920
8921 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
8922 {
8924 selfpacket.MoverGUID = GetGUID();
8925 selfpacket.SequenceIndex = m_movementCounter++;
8926 selfpacket.SpeedMin = min;
8927 selfpacket.SpeedMax = max;
8928 playerMover->GetSession()->SendPacket(selfpacket.Write());
8929 }
8930}
8931
8933{
8934 while (!m_followingMe.empty())
8935 (*m_followingMe.begin())->SetTarget(nullptr);
8936}
8937
8939{
8940 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
8941 m_deathState = s;
8942
8943 bool isOnVehicle = GetVehicle() != nullptr;
8944
8945 if (s != ALIVE && s != JUST_RESPAWNED)
8946 {
8947 CombatStop();
8948
8949 if (IsNonMeleeSpellCast(false))
8951
8952 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
8953 // vehicles use special type of charm that is not removed by the next function
8954 // triggering an assert
8958 }
8959
8960 if (s == JUST_DIED)
8961 {
8962 // remove aurastates allowing special moves
8965
8966 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
8967 if (!isOnVehicle)
8968 {
8969 if (GetMotionMaster()->StopOnDeath())
8970 DisableSpline();
8971 }
8972
8973 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
8974 // do not why since in IncreaseMaxHealth currenthealth is checked
8975 SetHealth(0);
8976 SetPower(GetPowerType(), 0);
8979
8980 if (m_vignette && !m_vignette->Data->GetFlags().HasFlag(VignetteFlags::PersistsThroughDeath))
8981 SetVignette(0);
8982
8983 // players in instance don't have ZoneScript, but they have InstanceScript
8984 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
8985 zoneScript->OnUnitDeath(this);
8986 }
8987 else if (s == JUST_RESPAWNED)
8988 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
8989}
8990
8991//======================================================================
8992
8994{
8995 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
8996 {
8997 AuraApplication* aurApp = itr->second;
8998 ++itr;
8999
9000 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, true);
9001 }
9002
9004 if (spell->getState() == SPELL_STATE_PREPARING
9005 && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_IN_COMBAT_ONLY_PEACEFUL)
9006 && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Combat))
9008
9011
9014}
9015
9017{
9018 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
9019 {
9020 AuraApplication* aurApp = itr->second;
9021 ++itr;
9022
9023 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, false);
9024 }
9025
9027
9030}
9031
9032void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
9033{
9034 if (!target->IsEngaged() && !canInitialAggro)
9035 return;
9036 target->EngageWithTarget(this);
9037 if (Unit* targetOwner = target->GetCharmerOrOwner())
9038 targetOwner->EngageWithTarget(this);
9039
9041 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
9042 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
9043 {
9044 myPlayerOwner->UpdatePvP(true);
9045 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
9047 }
9048}
9049
9051{
9052 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
9053
9054 bool state = false;
9055 for (Unit* minion : m_Controlled)
9056 if (minion->IsInCombat())
9057 {
9058 state = true;
9059 break;
9060 }
9061
9062 if (state)
9064 else
9066}
9067
9068void Unit::SetInteractionAllowedWhileHostile(bool interactionAllowed)
9069{
9070 if (interactionAllowed)
9072 else
9074
9076}
9077
9078void Unit::SetInteractionAllowedInCombat(bool interactionAllowed)
9079{
9080 if (interactionAllowed)
9082 else
9084
9085 if (IsInCombat())
9087}
9088
9090{
9091 if (m_unitData->NpcFlags)
9093 if (m_unitData->NpcFlags2)
9095}
9096
9097//======================================================================
9098
9100{
9101 DiminishingReturn const& diminish = m_Diminishing[group];
9102 if (!diminish.hitCount)
9103 return DIMINISHING_LEVEL_1;
9104
9105 // If last spell was cast more than 18 seconds ago - reset level.
9106 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 18 * IN_MILLISECONDS)
9107 return DIMINISHING_LEVEL_1;
9108
9109 return DiminishingLevels(diminish.hitCount);
9110}
9111
9112void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo)
9113{
9115 uint32 currentLevel = GetDiminishing(group);
9116 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel();
9117
9118 DiminishingReturn& diminish = m_Diminishing[group];
9119 if (currentLevel < maxLevel)
9120 diminish.hitCount = currentLevel + 1;
9121}
9122
9123bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
9124{
9125 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
9126 if (duration == -1 || group == DIMINISHING_NONE)
9127 return true;
9128
9129 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration();
9130
9131 // test pet/charm masters instead pets/charmeds
9132 Unit const* targetOwner = GetCharmerOrOwner();
9133 Unit const* casterOwner = caster->GetCharmerOrOwner();
9134
9135 if (limitDuration > 0 && duration > limitDuration)
9136 {
9137 Unit const* target = targetOwner ? targetOwner : this;
9138 WorldObject const* source = casterOwner ? casterOwner : caster;
9139
9140 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
9141 duration = limitDuration;
9142 }
9143
9144 float mod = 1.0f;
9145 switch (group)
9146 {
9147 case DIMINISHING_TAUNT:
9148 {
9149 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
9150 {
9151 DiminishingLevels diminish = previousLevel;
9152 switch (diminish)
9153 {
9154 case DIMINISHING_LEVEL_1: break;
9155 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
9156 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
9157 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
9158 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
9159 default: break;
9160 }
9161 }
9162 break;
9163 }
9165 {
9166 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9167 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9168 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9169 {
9170 DiminishingLevels diminish = previousLevel;
9171 switch (diminish)
9172 {
9173 case DIMINISHING_LEVEL_1: break;
9174 case DIMINISHING_LEVEL_2: mod = 0.0f; break;
9175 default: break;
9176 }
9177 }
9178 break;
9179 }
9180 default:
9181 {
9182 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9183 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9184 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9185 {
9186 DiminishingLevels diminish = previousLevel;
9187 switch (diminish)
9188 {
9189 case DIMINISHING_LEVEL_1: break;
9190 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
9191 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
9192 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
9193 default: break;
9194 }
9195 }
9196 break;
9197 }
9198 }
9199
9200 duration = int32(duration * mod);
9201 return (duration != 0);
9202}
9203
9205{
9206 // Checking for existing in the table
9207 DiminishingReturn& diminish = m_Diminishing[group];
9208
9209 if (apply)
9210 ++diminish.stack;
9211 else if (diminish.stack)
9212 {
9213 --diminish.stack;
9214
9215 // Remember time after last aura from group removed
9216 if (!diminish.stack)
9217 diminish.hitTime = GameTime::GetGameTimeMS();
9218 }
9219}
9220
9222{
9223 for (DiminishingReturn& dim : m_Diminishing)
9224 dim.Clear();
9225}
9226
9228{
9229 if (GetTypeId() == TYPEID_PLAYER)
9230 {
9232 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
9233 if (ssEntry && ssEntry->CreatureType > 0)
9234 return ssEntry->CreatureType;
9235 else
9236 {
9237 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
9238 return raceEntry->CreatureType;
9239 }
9240 }
9241 else
9242 return ToCreature()->GetCreatureTemplate()->type;
9243}
9244
9246{
9247 uint32 creatureType = GetCreatureType();
9248 return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0;
9249}
9250
9252{
9254}
9255
9256void Unit::CancelShapeshiftForm(bool onlyTravelShapeshiftForm /*= false*/, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool force /*= false*/)
9257{
9259 if (form == FORM_NONE)
9260 return;
9261
9262 bool isTravelShapeshiftForm = [form]()
9263 {
9264 if (SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form))
9265 {
9266 if (shapeInfo->MountTypeID)
9267 return true;
9268
9269 if (shapeInfo->ID == FORM_TRAVEL_FORM || shapeInfo->ID == FORM_AQUATIC_FORM)
9270 return true;
9271 }
9272
9273 return false;
9274 }();
9275
9276 if (onlyTravelShapeshiftForm && !isTravelShapeshiftForm)
9277 return;
9278
9280 for (AuraEffect* aurEff : shapeshifts)
9281 {
9282 SpellInfo const* spellInfo = aurEff->GetBase()->GetSpellInfo();
9283 if (force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive()))
9284 aurEff->GetBase()->Remove(removeMode);
9285 }
9286}
9287
9289{
9291 return form == FORM_CAT_FORM || form == FORM_BEAR_FORM || form == FORM_DIRE_BEAR_FORM || form == FORM_GHOST_WOLF;
9292}
9293
9295{
9297}
9298
9299bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
9300{
9301 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
9302 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_ALLOW_WHILE_MOUNTED))
9303 return false;
9304
9305 if (form)
9306 {
9307 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
9308 if (!shapeshift)
9309 return true;
9310
9311 if (!shapeshift->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance))
9312 return true;
9313 }
9314
9315 if (displayId == GetNativeDisplayId())
9316 return false;
9317
9318 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(displayId);
9319 if (!display)
9320 return true;
9321
9323 if (!displayExtra)
9324 return true;
9325
9326 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
9327 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
9328
9330 if (race && !race->GetFlags().HasFlag(ChrRacesFlag::CanMount))
9331 return true;
9332
9333 return false;
9334}
9335
9336/*#######################################
9337######## ########
9338######## STAT SYSTEM ########
9339######## ########
9340#######################################*/
9341
9342void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
9343{
9344 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9345 {
9346 TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!");
9347 return;
9348 }
9349
9350 if (!amount)
9351 return;
9352
9353 switch (modifierType)
9354 {
9355 case BASE_VALUE:
9357 case TOTAL_VALUE:
9358 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9359 break;
9360 default:
9361 break;
9362 }
9363
9364 UpdateUnitMod(unitMod);
9365}
9366
9367void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
9368{
9369 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9370 {
9371 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
9372 return;
9373 }
9374
9375 if (!pct)
9376 return;
9377
9378 switch (modifierType)
9379 {
9380 case BASE_PCT:
9381 case TOTAL_PCT:
9382 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9383 break;
9384 default:
9385 break;
9386 }
9387
9388 UpdateUnitMod(unitMod);
9389}
9390
9391void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9392{
9393 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9394 return;
9395
9396 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9397 UpdateUnitMod(unitMod);
9398}
9399
9400void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9401{
9402 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9403 return;
9404
9405 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9406 UpdateUnitMod(unitMod);
9407}
9408
9410{
9411 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9412 {
9413 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9414 return 0.0f;
9415 }
9416
9417 return m_auraFlatModifiersGroup[unitMod][modifierType];
9418}
9419
9421{
9422 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9423 {
9424 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9425 return 0.0f;
9426 }
9427
9428 return m_auraPctModifiersGroup[unitMod][modifierType];
9429}
9430
9432{
9433 if (!CanModifyStats())
9434 return;
9435
9436 switch (unitMod)
9437 {
9442
9443 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9444 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9445
9446 case UNIT_MOD_MANA:
9447 case UNIT_MOD_RAGE:
9448 case UNIT_MOD_FOCUS:
9449 case UNIT_MOD_ENERGY:
9451 case UNIT_MOD_RUNES:
9456 case UNIT_MOD_ALTERNATE:
9457 case UNIT_MOD_MAELSTROM:
9458 case UNIT_MOD_CHI:
9459 case UNIT_MOD_INSANITY:
9463 case UNIT_MOD_FURY:
9464 case UNIT_MOD_PAIN:
9465 case UNIT_MOD_ESSENCE:
9472
9479
9482
9486
9487 default:
9488 ABORT_MSG("Not implemented UnitMod %u", unitMod);
9489 break;
9490 }
9491}
9492
9493void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9494{
9495 UnitMods unitMod;
9496 switch (attackType)
9497 {
9498 case BASE_ATTACK:
9499 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9500 break;
9501 case OFF_ATTACK:
9502 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9503 break;
9504 case RANGED_ATTACK:
9505 unitMod = UNIT_MOD_DAMAGE_RANGED;
9506 break;
9507 default:
9508 ABORT();
9509 break;
9510 }
9511
9512 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9513 {
9514 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9515 return false;
9516
9517 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9518 });
9519
9520 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9521}
9522
9524{
9525 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
9527}
9528
9530{
9531 float factor;
9532 UnitMods unitMod;
9533 switch (attackType)
9534 {
9535 case BASE_ATTACK:
9536 factor = 1.0f;
9537 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9538 break;
9539 case OFF_ATTACK:
9540 // off hand has 50% penalty
9541 factor = 0.5f;
9542 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9543 break;
9544 case RANGED_ATTACK:
9545 factor = 1.0f;
9546 unitMod = UNIT_MOD_DAMAGE_RANGED;
9547 break;
9548 default:
9549 ABORT();
9550 break;
9551 }
9552
9553 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9554 {
9555 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9556 return false;
9557
9558 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9559 });
9560
9561 if (attackType == OFF_ATTACK)
9562 factor *= GetTotalAuraModifier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, [this, attackType](AuraEffect const* aurEff)
9563 {
9564 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9565 });
9566
9567 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9568}
9569
9571{
9572 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
9574}
9575
9577{
9578 float createStat = GetCreateStat(stat); // retrieved early to workaround a GCC false positive warning about out of bounds array access (conversion to UnitMods confuses it)
9579
9581
9582 // value = ((base_value * base_pct) + total_value) * total_pct
9583 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9584 value += createStat;
9585 value *= GetPctModifierValue(unitMod, BASE_PCT);
9586 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9587 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9588
9589 return value;
9590}
9591
9593{
9594 if (unitMod >= UNIT_MOD_END)
9595 {
9596 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9597 return 0.0f;
9598 }
9599
9600 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9601 value *= GetPctModifierValue(unitMod, BASE_PCT);
9602 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9603 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9604
9605 return value;
9606}
9607
9609{
9611
9612 switch (unitMod)
9613 {
9614 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9615 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9616 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9617 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9618 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9619 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9620
9621 default:
9622 break;
9623 }
9624
9625 return school;
9626}
9627
9629{
9630 Stats stat = STAT_STRENGTH;
9631
9632 switch (unitMod)
9633 {
9634 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9635 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9636 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9637 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9638 default:
9639 break;
9640 }
9641
9642 return stat;
9643}
9644
9646{
9647 if (school > SPELL_SCHOOL_NORMAL)
9648 {
9649 UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
9650
9651 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9652 value *= GetPctModifierValue(unitMod, BASE_PCT);
9653
9654 float baseValue = value;
9655
9656 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9657 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9658
9659 SetResistance(SpellSchools(school), int32(value));
9660 SetBonusResistanceMod(SpellSchools(school), int32(value - baseValue));
9661 }
9662 else
9663 UpdateArmor();
9664}
9665
9666float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon /*= true*/) const
9667{
9668 if (attType == RANGED_ATTACK)
9669 {
9670 float ap = m_unitData->RangedAttackPower + m_unitData->RangedAttackPowerModPos + m_unitData->RangedAttackPowerModNeg;
9671 if (includeWeapon)
9672 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9673 if (ap < 0)
9674 return 0.0f;
9675 return ap * (1.0f + m_unitData->RangedAttackPowerMultiplier);
9676 }
9677 else
9678 {
9679 float ap = m_unitData->AttackPower + m_unitData->AttackPowerModPos + m_unitData->AttackPowerModNeg;
9680 if (includeWeapon)
9681 {
9682 if (attType == BASE_ATTACK)
9683 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9684 else
9685 {
9686 ap += m_unitData->OffHandWeaponAttackPower;
9687 ap /= 2;
9688 }
9689 }
9690 if (ap < 0)
9691 return 0.0f;
9692 return ap * (1.0f + m_unitData->AttackPowerMultiplier);
9693 }
9694}
9695
9697{
9698 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9699 return 0.0f;
9700
9701 return m_weaponDamage[attType][type];
9702}
9703
9705{
9708}
9709
9710void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
9711{
9713
9714 if (!sendUpdate)
9715 return;
9716
9717 if (Player* player = ToPlayer())
9718 {
9719 // group update
9720 if (player->GetGroup())
9721 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9722
9723 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
9724 }
9725}
9726
9728{
9730 val = 0;
9731 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
9732 val = 1;
9733 else
9734 {
9735 uint64 maxHealth = GetMaxHealth();
9736 if (maxHealth < val)
9737 val = maxHealth;
9738 }
9739
9740 uint64 oldVal = GetHealth();
9742
9743 TriggerOnHealthChangeAuras(oldVal, val);
9744
9745 // group update
9746 if (Player* player = ToPlayer())
9747 {
9748 if (player->GetGroup())
9749 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9750 }
9751 else if (Pet* pet = ToCreature()->ToPet())
9752 {
9753 if (pet->isControlled())
9754 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
9755 }
9756}
9757
9759{
9760 if (!val)
9761 val = 1;
9762
9763 uint64 health = GetHealth();
9765
9766 // group update
9767 if (GetTypeId() == TYPEID_PLAYER)
9768 {
9769 if (ToPlayer()->GetGroup())
9771 }
9772 else if (Pet* pet = ToCreature()->ToPet())
9773 {
9774 if (pet->isControlled())
9775 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
9776 }
9777
9778 if (val < health)
9779 SetHealth(val);
9780}
9781
9783{
9784 uint32 powerIndex = GetPowerIndex(power);
9785 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9786 return 0;
9787
9788 return m_unitData->Power[powerIndex];
9789}
9790
9792{
9793 uint32 powerIndex = GetPowerIndex(power);
9794 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9795 return 0;
9796
9797 return m_unitData->MaxPower[powerIndex];
9798}
9799
9800void Unit::SetPower(Powers power, int32 val, bool withPowerUpdate /*= true*/)
9801{
9802 uint32 powerIndex = GetPowerIndex(power);
9803 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9804 return;
9805
9806 int32 maxPower = GetMaxPower(power);
9807 if (maxPower < val)
9808 val = maxPower;
9809
9810 int32 oldPower = m_unitData->Power[powerIndex];
9812
9813 if (IsInWorld() && withPowerUpdate)
9814 {
9816 packet.Guid = GetGUID();
9818 packet.Powers.emplace_back(val, power);
9820 }
9821
9822 TriggerOnPowerChangeAuras(power, oldPower, val);
9823
9824 // group update
9825 if (Player* player = ToPlayer())
9826 {
9827 if (player->GetGroup())
9828 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9829 }
9830 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
9831 {
9832 if (pet->isControlled())
9833 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
9834 }*/
9835}
9836
9838{
9839 uint32 powerIndex = GetPowerIndex(power);
9840 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9841 return;
9842
9843 int32 cur_power = GetPower(power);
9845
9846 // group update
9847 if (GetTypeId() == TYPEID_PLAYER)
9848 {
9849 if (ToPlayer()->GetGroup())
9851 }
9852 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
9853 {
9854 if (pet->isControlled())
9855 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
9856 }*/
9857
9858 if (val < cur_power)
9859 SetPower(power, val);
9860}
9861
9863{
9864 auto processAuras = [&](AuraEffectVector const& effects)
9865 {
9866 for (AuraEffect const* effect : effects)
9867 {
9868 if (effect->GetMiscValue() == power)
9869 {
9870 int32 effectAmount = effect->GetAmount();
9871 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
9872
9873 float oldValueCheck = oldVal;
9874 float newValueCheck = newVal;
9875
9876 if (effect->GetAuraType() == SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT)
9877 {
9878 int32 maxPower = GetMaxPower(power);
9879 if (!maxPower)
9880 continue;
9881
9882 oldValueCheck = GetPctOf(oldVal, maxPower);
9883 newValueCheck = GetPctOf(newVal, maxPower);
9884 }
9885
9886 switch (AuraTriggerOnPowerChangeDirection(effect->GetMiscValueB()))
9887 {
9889 if (oldValueCheck >= effect->GetAmount() || newValueCheck < effectAmount)
9890 continue;
9891 break;
9893 if (oldValueCheck <= effect->GetAmount() || newValueCheck > effectAmount)
9894 continue;
9895 break;
9896 default:
9897 break;
9898 }
9899
9900 CastSpell(this, triggerSpell, effect);
9901 }
9902 }
9903 };
9904
9907}
9908
9910{
9911 if (UnitAI* ai = GetAI())
9912 {
9913 m_aiLocked = true;
9914 ai->UpdateAI(diff);
9915 m_aiLocked = false;
9916 }
9917}
9918
9920{
9921 i_AIs.emplace(newAI);
9922}
9923
9925{
9926 PushAI(newAI);
9927 RefreshAI();
9928}
9929
9931{
9932 if (!i_AIs.empty())
9933 {
9934 i_AIs.pop();
9935 return true;
9936 }
9937 else
9938 return false;
9939}
9940
9942{
9943 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
9944 if (i_AIs.empty())
9945 i_AI = nullptr;
9946 else
9947 i_AI = i_AIs.top();
9948}
9949
9951{
9952 bool const charmed = IsCharmed();
9953
9954 if (charmed)
9956 else
9957 {
9959 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
9960 }
9961}
9962
9964{
9965 // Keep popping the stack until we either reach the bottom or find a valid AI
9966 while (PopAI())
9967 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
9968 return;
9969}
9970
9972{
9973 if (Creature* creature = ToCreature())
9974 return sCreatureAIRegistry->GetRegistryItem("ScheduledChangeAI")->Create(creature);
9975 else
9976 return nullptr;
9977}
9978
9980{
9981 if (UnitAI* ai = GetAI())
9982 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
9983 else
9984 return true;
9985}
9986
9988{
9990 i_motionMaster->AddToWorld();
9991
9993}
9994
9996{
9997 // cleanup
9998 ASSERT(GetGUID());
9999
10000 if (IsInWorld())
10001 {
10002 if (IsAreaSpiritHealer())
10003 {
10004 if (Creature* creature = ToCreature())
10005 creature->SummonGraveyardTeleporter();
10006 }
10007
10009 if (UnitAI* ai = GetAI())
10010 ai->OnDespawn();
10011
10012 if (IsVehicle())
10013 RemoveVehicleKit(true);
10014
10019
10023
10024 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
10027
10029
10031
10032 if (IsCharmed())
10033 RemoveCharmedBy(nullptr);
10034
10035 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
10036 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
10037
10038 if (Unit* owner = GetOwner())
10039 {
10040 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
10041 {
10042 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
10043 ABORT();
10044 }
10045 }
10046
10049 }
10050}
10051
10053{
10054 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
10056
10057 SetVignette(0);
10058
10059 if (IsInWorld())
10061 else
10062 {
10063 // cleanup that must happen even if not in world
10064 if (IsVehicle())
10065 RemoveVehicleKit(true);
10066 }
10067
10068 ASSERT(GetGUID());
10069
10070 // A unit may be in removelist and not in world, but it is still in grid
10071 // and may have some references during delete
10074
10075 if (finalCleanup)
10076 m_cleanupDone = true;
10077
10078 CombatStop();
10079}
10080
10081void Unit::CleanupsBeforeDelete(bool finalCleanup)
10082{
10083 CleanupBeforeRemoveFromMap(finalCleanup);
10084
10086}
10087
10089{
10090 if (IsCharmed())
10091 {
10092 UnitAI* newAI = nullptr;
10093 if (GetTypeId() == TYPEID_PLAYER)
10094 {
10095 if (Unit* charmer = GetCharmer())
10096 {
10097 // first, we check if the creature's own AI specifies an override playerai for its owned players
10098 if (Creature* creatureCharmer = charmer->ToCreature())
10099 {
10100 if (CreatureAI* charmerAI = creatureCharmer->AI())
10101 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
10102 }
10103 else
10104 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
10105 }
10106 if (!newAI) // otherwise, we default to the generic one
10107 newAI = new SimpleCharmedPlayerAI(ToPlayer());
10108 }
10109 else
10110 {
10112 if (isPossessed() || IsVehicle())
10113 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature());
10114 else
10115 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature());
10116 }
10117
10118 ASSERT(newAI);
10119 SetAI(newAI);
10120 newAI->OnCharmed(true);
10121 }
10122 else
10123 {
10125 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
10126 RefreshAI();
10127 if (UnitAI* ai = GetAI())
10128 ai->OnCharmed(true);
10129 }
10130}
10131
10133{
10134 if (!m_charmInfo)
10135 m_charmInfo = std::make_unique<CharmInfo>(this);
10136
10137 return m_charmInfo.get();
10138}
10139
10141{
10142 if (!m_charmInfo)
10143 return;
10144
10145 m_charmInfo->RestoreState();
10146 m_charmInfo = nullptr;
10147}
10148
10150{
10154
10156 packet.MoverGUID = target->GetGUID();
10157 ToPlayer()->SendDirectMessage(packet.Write());
10158}
10159
10161{
10162 ProcFlagsHit hitMask = PROC_HIT_NONE;
10163 // Check victim state
10164 if (missCondition != SPELL_MISS_NONE)
10165 {
10166 switch (missCondition)
10167 {
10168 case SPELL_MISS_MISS:
10169 hitMask |= PROC_HIT_MISS;
10170 break;
10171 case SPELL_MISS_DODGE:
10172 hitMask |= PROC_HIT_DODGE;
10173 break;
10174 case SPELL_MISS_PARRY:
10175 hitMask |= PROC_HIT_PARRY;
10176 break;
10177 case SPELL_MISS_BLOCK:
10178 // spells can't be partially blocked (it's damage can though)
10180 break;
10181 case SPELL_MISS_EVADE:
10182 hitMask |= PROC_HIT_EVADE;
10183 break;
10184 case SPELL_MISS_IMMUNE:
10185 case SPELL_MISS_IMMUNE2:
10186 hitMask |= PROC_HIT_IMMUNE;
10187 break;
10188 case SPELL_MISS_DEFLECT:
10189 hitMask |= PROC_HIT_DEFLECT;
10190 break;
10191 case SPELL_MISS_ABSORB:
10192 hitMask |= PROC_HIT_ABSORB;
10193 break;
10194 case SPELL_MISS_REFLECT:
10195 hitMask |= PROC_HIT_REFLECT;
10196 break;
10197 case SPELL_MISS_RESIST:
10198 hitMask |= PROC_HIT_FULL_RESIST;
10199 break;
10200 default:
10201 break;
10202 }
10203 }
10204 else
10205 {
10206 // On block
10207 if (damageInfo->blocked)
10208 {
10209 hitMask |= PROC_HIT_BLOCK;
10210 if (damageInfo->fullBlock)
10211 hitMask |= PROC_HIT_FULL_BLOCK;
10212 }
10213 // On absorb
10214 if (damageInfo->absorb)
10215 hitMask |= PROC_HIT_ABSORB;
10216
10217 // Don't set hit/crit hitMask if damage is nullified
10218 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
10219 if (!damageNullified)
10220 {
10221 // On crit
10222 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10223 hitMask |= PROC_HIT_CRITICAL;
10224 else
10225 hitMask |= PROC_HIT_NORMAL;
10226 }
10227 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
10228 hitMask |= PROC_HIT_FULL_RESIST;
10229 }
10230
10231 return hitMask;
10232}
10233
10234void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, ProcFlagsInit const& typeMask, ProcFlagsHit hitMask, WeaponAttackType /*attType*/)
10235{
10236 // Player is loaded now - do not allow passive spell casts to proc
10237 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
10238 return;
10239
10240 // For melee/ranged based attack need update skills and set some Aura states if victim present
10241 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
10242 {
10243 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10245 {
10246 // for victim
10247 if (isVictim)
10248 {
10249 // if victim and dodge attack
10250 if (hitMask & PROC_HIT_DODGE)
10251 {
10252 // Update AURA_STATE on dodge
10253 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
10254 {
10257 }
10258 }
10259 // if victim and parry attack
10260 if (hitMask & PROC_HIT_PARRY)
10261 {
10264 }
10265 // if and victim block attack
10266 if (hitMask & PROC_HIT_BLOCK)
10267 {
10270 }
10271 }
10272 }
10273 }
10274}
10275
10277{
10278 TimePoint now = GameTime::Now();
10279
10280 auto processAuraApplication = [&](AuraApplication* aurApp)
10281 {
10282 if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
10283 {
10284 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
10285 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
10286 }
10287 else
10288 {
10289 if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE))
10290 {
10291 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10292 {
10293 aurApp->GetBase()->PrepareProcChargeDrop(procEntry, eventInfo);
10294 aurasTriggeringProc.emplace_back(0, aurApp);
10295 }
10296 }
10297
10298 if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE))
10299 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10300 aurApp->GetBase()->AddProcCooldown(procEntry, now);
10301 }
10302 };
10303
10304 // use provided list of auras which can proc
10305 if (procAuras)
10306 {
10307 for (AuraApplication* aurApp : *procAuras)
10308 {
10309 ASSERT(aurApp->GetTarget() == this);
10310 processAuraApplication(aurApp);
10311 }
10312 }
10313 // or generate one on our own
10314 else
10315 {
10316 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
10317 processAuraApplication(itr->second);
10318 }
10319}
10320
10321void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras, Unit* actionTarget,
10322 ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget, ProcFlagsSpellType spellTypeMask,
10323 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
10324{
10325 // prepare data for self trigger
10326 ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10327 AuraApplicationProcContainer myAurasTriggeringProc;
10328 if (typeMaskActor)
10329 {
10330 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
10331
10332 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
10333 if (Player* modOwner = GetSpellModOwner())
10334 {
10335 if (modOwner != this && spell)
10336 {
10337 AuraApplicationList modAuras;
10338 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
10339 {
10340 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
10341 modAuras.push_front(itr->second);
10342 }
10343 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
10344 }
10345 }
10346 }
10347
10348 // prepare data for target trigger
10349 ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10350 AuraApplicationProcContainer targetAurasTriggeringProc;
10351 if (typeMaskActionTarget && actionTarget)
10352 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
10353
10354 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
10355
10356 if (typeMaskActionTarget && actionTarget)
10357 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
10358}
10359
10361{
10362 Spell const* triggeringSpell = eventInfo.GetProcSpell();
10363 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
10364
10365 int32 oldProcChainLength = std::exchange(m_procChainLength, std::max(m_procChainLength + 1, triggeringSpell ? triggeringSpell->GetProcChainLength() : 0));
10366
10367 if (disableProcs)
10368 SetCantProc(true);
10369
10370 for (auto const& [procEffectMask, aurApp] : aurasTriggeringProc)
10371 {
10372 if (aurApp->GetRemoveMode())
10373 continue;
10374
10375 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
10376 }
10377
10378 if (disableProcs)
10379 SetCantProc(false);
10380
10381 m_procChainLength = oldProcChainLength;
10382}
10383
10386{
10387 Unit* owner = GetOwner();
10388 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10389 return;
10390
10391 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10392 petActionFeedback.SpellID = spellId;
10393 petActionFeedback.Response = msg;
10394 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10395}
10396
10398{
10399 Unit* owner = GetOwner();
10400 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10401 return;
10402
10403 WorldPackets::Pet::PetActionSound petActionSound;
10404 petActionSound.UnitGUID = GetGUID();
10405 petActionSound.Action = pettalk;
10406 owner->ToPlayer()->SendDirectMessage(petActionSound.Write());
10407}
10408
10410{
10411 Unit* owner = GetOwner();
10412 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10413 return;
10414
10416 packet.UnitGUID = guid;
10418 owner->ToPlayer()->SendDirectMessage(packet.Write());
10419}
10420
10422
10424{
10426}
10427
10429{
10430 return IDLE_MOTION_TYPE;
10431}
10432
10434{
10436
10437 // not need send any packets if not in world or not moving
10438 if (!IsInWorld() || movespline->Finalized())
10439 return;
10440
10441 // Update position now since Stop does not start a new movement that can be updated later
10442 if (movespline->HasStarted())
10444 Movement::MoveSplineInit init(this);
10445 init.Stop();
10446}
10447
10448void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10449{
10450 if (IsInvalidMovementSlot(slot))
10451 return;
10452
10453 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10454 movementGenerator->Pause(timer);
10455
10456 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10457 StopMoving();
10458}
10459
10460void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10461{
10462 if (IsInvalidMovementSlot(slot))
10463 return;
10464
10465 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10466 movementGenerator->Resume(timer);
10467}
10468
10470{
10472 return
10476}
10477
10479{
10482}
10483
10484void Unit::SetStandState(UnitStandStateType state, uint32 animKitID /* = 0*/)
10485{
10487
10488 if (IsStandState())
10490
10491 if (GetTypeId() == TYPEID_PLAYER)
10492 {
10493 WorldPackets::Misc::StandStateUpdate packet(state, animKitID);
10494 ToPlayer()->SendDirectMessage(packet.Write());
10495 }
10496}
10497
10498void Unit::SetAnimTier(AnimTier animTier, bool notifyClient /*= true*/)
10499{
10501
10502 if (notifyClient)
10503 {
10505 setAnimTier.Unit = GetGUID();
10506 setAnimTier.Tier = AsUnderlyingType(animTier);
10507 SendMessageToSet(setAnimTier.Write(), true);
10508 }
10509}
10510
10512{
10513 uint32 transformId = GetTransformSpell();
10514 if (!transformId)
10515 return false;
10516
10517 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId, GetMap()->GetDifficultyID());
10518 if (!spellInfo)
10519 return false;
10520
10521 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10522}
10523
10525{
10527 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10528 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1 : 0.01;
10529 SetObjectScale(std::max(scale, scaleMin));
10530}
10531
10532void Unit::SetDisplayId(uint32 displayId, bool setNative /*= false*/)
10533{
10534 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
10535
10536 if (IsCreature() && !IsPet())
10537 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
10538 displayScale = model->DisplayScale;
10539
10542
10543 if (setNative)
10544 {
10547 }
10548
10549 // Set Gender by ModelInfo
10550 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(displayId))
10551 SetGender(Gender(modelInfo->gender));
10552
10554}
10555
10556void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false*/)
10557{
10558 AuraEffect* handledAura = nullptr;
10559 // try to receive model from transform auras
10561 if (!transforms.empty())
10562 {
10563 // iterate over already applied transform auras - from newest to oldest
10564 for (auto i = transforms.begin(); i != transforms.end(); ++i)
10565 {
10566 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10567 {
10568 if (!handledAura)
10569 {
10570 if (!ignorePositiveAurasPreventingMounting)
10571 handledAura = (*i);
10572 else if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*i)->GetMiscValue()))
10574 handledAura = (*i);
10575 }
10576 // prefer negative auras
10577 if (!aurApp->IsPositive())
10578 {
10579 handledAura = (*i);
10580 break;
10581 }
10582 }
10583 }
10584 }
10585
10587
10588 // transform aura was found
10589 if (handledAura)
10590 {
10591 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10592 return;
10593 }
10594 // we've found shapeshift
10595 else if (!shapeshiftAura.empty()) // we've found shapeshift
10596 {
10597 // only one such aura possible at a time
10598 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10599 {
10600 if (!ignorePositiveAurasPreventingMounting || !IsDisallowedMountForm(0, GetShapeshiftForm(), modelId))
10601 SetDisplayId(modelId);
10602 else
10604 return;
10605 }
10606 }
10607 // no auras found - set modelid to default
10609}
10610
10612{
10613 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10614 m_reactiveTimer[i] = 0;
10615
10620}
10621
10623{
10624 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10625 {
10626 ReactiveType reactive = ReactiveType(i);
10627
10628 if (!m_reactiveTimer[reactive])
10629 continue;
10630
10631 if (m_reactiveTimer[reactive] <= p_time)
10632 {
10633 m_reactiveTimer[reactive] = 0;
10634
10635 switch (reactive)
10636 {
10637 case REACTIVE_DEFENSE:
10640 break;
10641 case REACTIVE_DEFENSE_2:
10644 break;
10645 default:
10646 break;
10647 }
10648 }
10649 else
10650 {
10651 m_reactiveTimer[reactive] -= p_time;
10652 }
10653 }
10654}
10655
10656Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10657{
10658 std::list<Unit*> targets;
10659 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10661 Cell::VisitAllObjects(this, searcher, dist);
10662
10663 // remove current target
10664 if (GetVictim())
10665 targets.remove(GetVictim());
10666
10667 if (exclude)
10668 targets.remove(exclude);
10669
10670 // remove not LoS targets
10671 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10672 {
10673 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10674 targets.erase(tIter++);
10675 else
10676 ++tIter;
10677 }
10678
10679 // no appropriate targets
10680 if (targets.empty())
10681 return nullptr;
10682
10683 // select random
10685}
10686
10688{
10689 return m_baseAttackSpeed[att];
10690}
10691
10693{
10694 m_baseAttackSpeed[att] = val;
10696}
10697
10699{
10700 switch (att)
10701 {
10702 case BASE_ATTACK:
10703 case OFF_ATTACK:
10705 break;
10706 case RANGED_ATTACK:
10708 break;
10709 default:
10710 break;;
10711 }
10712}
10713
10714void ApplyPercentModFloatVar(float& var, float val, bool apply)
10715{
10716 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
10717}
10718
10720{
10721 float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]);
10722 if (val > 0.f)
10723 {
10725
10726 if (att == BASE_ATTACK)
10728 else if (att == RANGED_ATTACK)
10730 }
10731 else
10732 {
10734
10735 if (att == BASE_ATTACK)
10737 else if (att == RANGED_ATTACK)
10739 }
10740
10742 m_attackTimer[att] = uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att] * remainingTimePct);
10743}
10744
10746{
10747 if (val > 0.f)
10748 {
10752 }
10753 else
10754 {
10758 }
10759}
10760
10762{
10763 if (Player* player = ToPlayer())
10764 {
10765 if (player->GetGroup())
10766 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
10767 }
10768 else if (GetTypeId() == TYPEID_UNIT && IsPet())
10769 {
10770 Pet* pet = ((Pet*)this);
10771 if (pet->isControlled())
10773 }
10774}
10775
10777{
10778 if (apply)
10779 ++m_procDeep;
10780 else
10781 {
10783 --m_procDeep;
10784 }
10785}
10786
10787float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
10788{
10789 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
10790 return GetBaseAttackTime(attType) / 1000.0f;
10791
10792 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
10793 if (!weapon)
10794 return 2.0f;
10795
10796 if (!normalized)
10797 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10798
10799 switch (weapon->GetTemplate()->GetSubClass())
10800 {
10807 return 3.3f;
10815 return 2.4f;
10817 return 1.7f;
10819 return 2.0f;
10820 default:
10821 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10822 }
10823}
10824
10825Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
10826{
10827 if (GetTypeId() != TYPEID_PLAYER)
10828 return nullptr;
10829
10830 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10831
10832 if (!pet->CreateBaseAtCreature(creatureTarget))
10833 {
10834 delete pet;
10835 return nullptr;
10836 }
10837
10838 uint8 level = creatureTarget->GetLevelForTarget(this) + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget->GetLevelForTarget(this);
10839
10840 if (!InitTamedPet(pet, level, spell_id))
10841 {
10842 delete pet;
10843 return nullptr;
10844 }
10845
10846 return pet;
10847}
10848
10850{
10851 if (GetTypeId() != TYPEID_PLAYER)
10852 return nullptr;
10853
10854 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
10855 if (!creatureInfo)
10856 return nullptr;
10857
10858 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10859
10860 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
10861 {
10862 delete pet;
10863 return nullptr;
10864 }
10865
10866 return pet;
10867}
10868
10869bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
10870{
10871 Player* player = ToPlayer();
10872 PetStable& petStable = player->GetOrInitPetStable();
10873 auto freeActiveSlotItr = std::find_if(petStable.ActivePets.begin(), petStable.ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
10874 {
10875 return !petInfo.has_value();
10876 });
10877
10878 if (freeActiveSlotItr == petStable.ActivePets.end())
10879 return false;
10880
10881 pet->SetCreatorGUID(GetGUID());
10882 pet->SetFaction(GetFaction());
10883 pet->SetCreatedBySpell(spell_id);
10885
10886 if (!pet->InitStatsForLevel(level))
10887 {
10888 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
10889 return false;
10890 }
10891
10893
10894 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
10895 // this enables pet details window (Shift+P)
10896 pet->InitPetCreateSpells();
10897 //pet->InitLevelupSpellsForLevel();
10898 pet->SetFullHealth();
10899
10900 petStable.SetCurrentActivePetIndex(std::distance(petStable.ActivePets.begin(), freeActiveSlotItr));
10901 pet->FillPetInfo(&freeActiveSlotItr->emplace());
10902 player->AddPetToUpdateFields(**freeActiveSlotItr, PetSaveMode(*petStable.GetCurrentActivePetIndex()), PET_STABLE_ACTIVE);
10903 return true;
10904}
10905
10907{
10909 packet.Percent = percent;
10910 receiver->GetSession()->SendPacket(packet.Write());
10911}
10912
10914{
10915 if (!sAnimKitStore.LookupEntry(animKitId))
10916 {
10917 TC_LOG_ERROR("entities.unit", "Unit::PlayOneShotAnimKitId using invalid AnimKit ID: {}", animKitId);
10918 return;
10919 }
10920
10922 data.Unit = GetGUID();
10923 data.AnimKitID = animKitId;
10924 SendMessageToSet(data.Write(), true);
10925}
10926
10928{
10929 if (_aiAnimKitId == animKitId)
10930 return;
10931
10932 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10933 return;
10934
10935 _aiAnimKitId = animKitId;
10936
10938 data.Unit = GetGUID();
10939 data.AnimKitID = animKitId;
10940 SendMessageToSet(data.Write(), true);
10941}
10942
10944{
10945 if (_movementAnimKitId == animKitId)
10946 return;
10947
10948 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10949 return;
10950
10951 _movementAnimKitId = animKitId;
10952
10954 data.Unit = GetGUID();
10955 data.AnimKitID = animKitId;
10956 SendMessageToSet(data.Write(), true);
10957}
10958
10960{
10961 if (_meleeAnimKitId == animKitId)
10962 return;
10963
10964 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10965 return;
10966
10967 _meleeAnimKitId = animKitId;
10968
10970 data.Unit = GetGUID();
10971 data.AnimKitID = animKitId;
10972 SendMessageToSet(data.Write(), true);
10973}
10974
10975/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/, bool skipSettingDeathState /*= false*/)
10976{
10977 // Prevent killing unit twice (and giving reward from kill twice)
10978 if (!victim->GetHealth())
10979 return;
10980
10981 if (attacker && !attacker->IsInMap(victim))
10982 attacker = nullptr;
10983
10984 // find player: owner of controlled `this` or `this` itself maybe
10985 Player* player = nullptr;
10986 if (attacker)
10987 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
10988
10989 Creature* creature = victim->ToCreature();
10990
10991 bool isRewardAllowed = attacker != victim;
10992 if (creature)
10993 isRewardAllowed = isRewardAllowed && !creature->GetTapList().empty();
10994
10995 std::vector<Player*> tappers;
10996 if (isRewardAllowed && creature)
10997 {
10998 for (ObjectGuid tapperGuid : creature->GetTapList())
10999 if (Player* tapper = ObjectAccessor::GetPlayer(*creature, tapperGuid))
11000 tappers.push_back(tapper);
11001
11002 if (!creature->CanHaveLoot())
11003 isRewardAllowed = false;
11004 }
11005
11006 // Exploit fix
11007 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
11008 isRewardAllowed = false;
11009
11010 // Reward player, his pets, and group/raid members
11011 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
11012 if (isRewardAllowed)
11013 {
11014 std::unordered_set<Group*> groups;
11015 for (Player* tapper : tappers)
11016 {
11017 if (Group* tapperGroup = tapper->GetGroup())
11018 {
11019 if (groups.insert(tapperGroup).second)
11020 {
11022 partyKillLog.Player = player && tapperGroup->IsMember(player->GetGUID()) ? player->GetGUID() : tapper->GetGUID();
11023 partyKillLog.Victim = victim->GetGUID();
11024 partyKillLog.Write();
11025
11026 tapperGroup->BroadcastPacket(partyKillLog.GetRawPacket(), tapperGroup->GetMemberGroup(tapper->GetGUID()) != 0);
11027
11028 if (creature)
11029 tapperGroup->UpdateLooterGuid(creature, true);
11030 }
11031 }
11032 else
11033 {
11035 partyKillLog.Player = tapper->GetGUID();
11036 partyKillLog.Victim = victim->GetGUID();
11037 tapper->SendDirectMessage(partyKillLog.Write());
11038 }
11039 }
11040
11041 // Generate loot before updating looter
11042 if (creature)
11043 {
11044 DungeonEncounterEntry const* dungeonEncounter = nullptr;
11045 if (InstanceScript const* instance = creature->GetInstanceScript())
11046 dungeonEncounter = instance->GetBossDungeonEncounter(creature);
11047
11048 if (creature->GetMap()->IsDungeon())
11049 {
11050 if (dungeonEncounter)
11051 {
11052 creature->m_personalLoot = GenerateDungeonEncounterPersonalLoot(dungeonEncounter->ID, creature->GetLootId(),
11054 creature->GetLootMode(), creature->GetMap()->GetMapDifficulty(), tappers);
11055 }
11056 else if (!tappers.empty())
11057 {
11058 Group* group = !groups.empty() ? *groups.begin() : nullptr;
11059 Player* looter = group ? ASSERT_NOTNULL(ObjectAccessor::GetPlayer(*creature, group->GetLooterGuid())) : tappers[0];
11060
11061 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, dungeonEncounter ? group : nullptr);
11062
11063 if (uint32 lootid = creature->GetLootId())
11064 loot->FillLoot(lootid, LootTemplates_Creature, looter, dungeonEncounter != nullptr, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), looter));
11065
11066 if (creature->GetLootMode() > 0)
11068
11069 if (group)
11070 loot->NotifyLootList(creature->GetMap());
11071
11072 creature->m_personalLoot[looter->GetGUID()].reset(loot); // trash mob loot is personal, generated with round robin rules
11073
11074 // Update round robin looter only if the creature had loot
11075 if (!loot->isLooted())
11076 for (Group* tapperGroup : groups)
11077 tapperGroup->UpdateLooterGuid(creature);
11078 }
11079 }
11080 else
11081 {
11082 for (Player* tapper : tappers)
11083 {
11084 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, nullptr);
11085
11086 if (dungeonEncounter)
11087 loot->SetDungeonEncounterId(dungeonEncounter->ID);
11088
11089 if (uint32 lootid = creature->GetLootId())
11090 loot->FillLoot(lootid, LootTemplates_Creature, tapper, true, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), tapper));
11091
11092 if (creature->GetLootMode() > 0)
11094
11095 creature->m_personalLoot[tapper->GetGUID()].reset(loot);
11096 }
11097 }
11098 }
11099
11100 if (Vignettes::VignetteData const* vignette = victim->GetVignette())
11101 {
11102 for (Player* tapper : tappers)
11103 {
11104 if (Quest const* reward = sObjectMgr->GetQuestTemplate(vignette->Data->RewardQuestID))
11105 tapper->RewardQuest(reward, LootItemType::Item, 0, victim, false);
11106
11107 if (vignette->Data->VisibleTrackingQuestID)
11108 tapper->SetRewardedQuest(vignette->Data->VisibleTrackingQuestID);
11109 }
11110 }
11111
11112 KillRewarder(Trinity::IteratorPair(tappers.data(), tappers.data() + tappers.size()), victim, false).Reward();
11113 }
11114
11115 // 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
11116 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
11117 {
11118 // proc only once for victim
11119 if (Unit* owner = attacker->GetOwner())
11121 }
11122
11123 if (!victim->IsCritter())
11124 {
11126
11127 for (Player* tapper : tappers)
11128 if (tapper->IsAtGroupRewardDistance(victim))
11130 }
11131
11132 // Proc auras on death - must be before aura/combat remove
11134
11135 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
11136 // and before Spirit of Redemption as it also removes auras
11137 if (attacker)
11138 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
11139 killerPlayer->UpdateCriteria(CriteriaType::DeliveredKillingBlow, 1, 0, 0, victim);
11140
11141 if (!skipSettingDeathState)
11142 {
11143 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
11144 victim->setDeathState(JUST_DIED);
11145 }
11146
11147 // Inform pets (if any) when player kills target)
11148 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
11149 // selection will get stuck on same target and break pet react state
11150 for (Player* tapper : tappers)
11151 {
11152 Pet* pet = tapper->GetPet();
11153 if (pet && pet->IsAlive() && pet->isControlled())
11154 {
11155 if (pet->IsAIEnabled())
11156 pet->AI()->KilledUnit(victim);
11157 else
11158 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
11159 }
11160 }
11161
11162 // 10% durability loss on death
11163 if (Player* plrVictim = victim->ToPlayer())
11164 {
11165 // remember victim PvP death for corpse type and corpse reclaim delay
11166 // at original death (not at SpiritOfRedemtionTalent timeout)
11167 plrVictim->SetPvPDeath(player != nullptr);
11168
11169 // only if not player and not controlled by player pet. And not at BG
11170 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
11171 {
11172 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
11173 uint32 loss = uint32(baseLoss - (baseLoss * plrVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS)));
11174 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", loss);
11175 // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss
11176 plrVictim->DurabilityLossAll(baseLoss, false);
11177 // durability lost message
11178 plrVictim->SendDurabilityLoss(plrVictim, loss);
11179 }
11180 // Call KilledUnit for creatures
11181 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11182 attacker->ToCreature()->AI()->KilledUnit(victim);
11183
11184 // last damage from non duel opponent or opponent controlled creature
11185 if (plrVictim->duel)
11186 {
11187 plrVictim->duel->Opponent->CombatStopWithPets(true);
11188 plrVictim->CombatStopWithPets(true);
11189 plrVictim->DuelComplete(DUEL_INTERRUPTED);
11190 }
11191 }
11192 else // creature died
11193 {
11194 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
11195 ASSERT_NODEBUGINFO(creature);
11196
11197 if (!creature->IsPet())
11198 {
11199 // must be after setDeathState which resets dynamic flags
11200 if (!creature->IsFullyLooted())
11202 else
11203 creature->AllLootRemovedFromCorpse();
11204
11206 {
11209 }
11210 }
11211
11212 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
11213 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11214 attacker->ToCreature()->AI()->KilledUnit(victim);
11215
11216 // Call creature just died function
11217 if (CreatureAI* ai = creature->AI())
11218 {
11219 ai->OnHealthDepleted(attacker, true);
11220 ai->JustDied(attacker);
11221 }
11222
11223 if (TempSummon * summon = creature->ToTempSummon())
11224 {
11225 if (WorldObject * summoner = summon->GetSummoner())
11226 {
11227 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
11228 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
11229 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
11230 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
11231 }
11232 }
11233 }
11234
11235 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
11236 // handle player kill only if not suicide (spirit of redemption for example)
11237 if (player && attacker != victim)
11238 {
11239 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
11240 pvp->HandleKill(player, victim);
11241
11242 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
11243 bf->HandleKill(player, victim);
11244 }
11245
11246 //if (victim->GetTypeId() == TYPEID_PLAYER)
11247 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
11248 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
11249
11250 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
11251 if (attacker)
11252 {
11253 if (BattlegroundMap* bgMap = victim->GetMap()->ToBattlegroundMap())
11254 {
11255 if (Battleground* bg = bgMap->GetBG())
11256 {
11257 if (Player* playerVictim = victim->ToPlayer())
11258 {
11259 if (player)
11260 bg->HandleKillPlayer(playerVictim, player);
11261 }
11262 else
11263 bg->HandleKillUnit(victim->ToCreature(), attacker);
11264 }
11265 }
11266 }
11267
11268 // achievement stuff
11269 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
11270 {
11271 if (attacker->GetTypeId() == TYPEID_UNIT)
11273 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
11275 }
11276
11277 // Hook for OnPVPKill Event
11278 if (attacker)
11279 {
11280 if (Player* killerPlr = attacker->ToPlayer())
11281 {
11282 if (Player* killedPlr = victim->ToPlayer())
11283 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
11284 else if (Creature* killedCre = victim->ToCreature())
11285 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
11286 }
11287 else if (Creature* killerCre = attacker->ToCreature())
11288 {
11289 if (Player* killed = victim->ToPlayer())
11290 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
11291 }
11292 }
11293}
11294
11296{
11297 if (apply)
11298 {
11299 if (HasUnitState(state))
11300 return;
11301
11302 if (state & UNIT_STATE_CONTROLLED)
11303 CastStop();
11304
11305 AddUnitState(state);
11306 switch (state)
11307 {
11308 case UNIT_STATE_STUNNED:
11309 SetStunned(true);
11310 break;
11311 case UNIT_STATE_ROOT:
11313 SetRooted(true);
11314 break;
11317 {
11319 // SendAutoRepeatCancel ?
11320 SetConfused(true);
11321 }
11322 break;
11323 case UNIT_STATE_FLEEING:
11325 {
11327 // SendAutoRepeatCancel ?
11328 SetFeared(true);
11329 }
11330 break;
11331 default:
11332 break;
11333 }
11334 }
11335 else
11336 {
11337 switch (state)
11338 {
11339 case UNIT_STATE_STUNNED:
11341 return;
11342
11343 ClearUnitState(state);
11344 SetStunned(false);
11345 break;
11346 case UNIT_STATE_ROOT:
11348 return;
11349
11350 ClearUnitState(state);
11352 SetRooted(false);
11353 break;
11356 return;
11357
11358 ClearUnitState(state);
11359 SetConfused(false);
11360 break;
11361 case UNIT_STATE_FLEEING:
11363 return;
11364
11365 ClearUnitState(state);
11366 SetFeared(false);
11367 break;
11368 default:
11369 return;
11370 }
11371
11373 }
11374}
11375
11377{
11378 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
11380 SetStunned(true);
11381
11383 SetRooted(true);
11384
11386 SetConfused(true);
11387
11389 SetFeared(true);
11390}
11391
11393{
11394 if (apply)
11395 {
11398
11399 StopMoving();
11400
11401 if (GetTypeId() == TYPEID_PLAYER)
11403
11404 SetRooted(true);
11405
11406 CastStop();
11407 }
11408 else
11409 {
11410 if (IsAlive() && GetVictim())
11412
11413 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11414 Unit* owner = GetCharmerOrOwner();
11415 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11417
11418 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11419 SetRooted(false);
11420 }
11421}
11422
11423void Unit::SetRooted(bool apply, bool packetOnly /*= false*/)
11424{
11425 if (!packetOnly)
11426 {
11427 if (apply)
11428 {
11429 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11430 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11431 // setting MOVEMENTFLAG_ROOT
11434 StopMoving();
11435 }
11436 else
11438 }
11439
11440 static OpcodeServer const rootOpcodeTable[2][2] =
11441 {
11444 };
11445
11446 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
11447 {
11448 WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]);
11449 packet.MoverGUID = GetGUID();
11451 playerMover->SendDirectMessage(packet.Write());
11452
11454 moveUpdate.Status = &m_movementInfo;
11455 SendMessageToSet(moveUpdate.Write(), playerMover);
11456 }
11457 else
11458 {
11459 WorldPackets::Movement::MoveSplineSetFlag packet(rootOpcodeTable[apply][0]);
11460 packet.MoverGUID = GetGUID();
11461 SendMessageToSet(packet.Write(), true);
11462 }
11463}
11464
11466{
11467 if (apply)
11468 {
11470
11471 Unit* caster = nullptr;
11473 if (!fearAuras.empty())
11474 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11475 if (!caster)
11476 caster = getAttackerForHelper();
11477 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)) : 0ms); // caster == NULL processed in MoveFleeing
11479 }
11480 else
11481 {
11483 if (IsAlive())
11484 {
11486 if (Unit const* victim = GetVictim())
11487 SetTarget(victim->GetGUID());
11488 if (!IsPlayer() && !IsInCombat())
11490 }
11491 }
11492
11493 // block / allow control to real player in control (eg charmer)
11494 if (GetTypeId() == TYPEID_PLAYER)
11495 {
11496 if (m_playerMovingMe)
11498 }
11499}
11500
11502{
11503 if (apply)
11504 {
11507 }
11508 else
11509 {
11510 if (IsAlive())
11511 {
11513 if (GetVictim())
11515 }
11516 }
11517
11518 // block / allow control to real player in control (eg charmer)
11519 if (GetTypeId() == TYPEID_PLAYER)
11520 {
11521 if (m_playerMovingMe)
11523 }
11524}
11525
11526bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11527{
11528 if (!charmer)
11529 return false;
11530
11531 // dismount players when charmed
11532 if (GetTypeId() == TYPEID_PLAYER)
11534
11535 if (charmer->GetTypeId() == TYPEID_PLAYER)
11537
11538 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11539 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11540
11541 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11542
11543 if (this == charmer)
11544 {
11545 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11546 return false;
11547 }
11548
11549 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11550 // return false;
11551
11553 {
11554 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11555 return false;
11556 }
11557
11558 // Already charmed
11559 if (!GetCharmerGUID().IsEmpty())
11560 {
11561 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11562 return false;
11563 }
11564
11565 CastStop();
11566 AttackStop();
11567
11568 Player* playerCharmer = charmer->ToPlayer();
11569
11570 // Charmer stop charming
11571 if (playerCharmer)
11572 {
11573 playerCharmer->StopCastingCharm();
11574 playerCharmer->StopCastingBindSight();
11575 }
11576
11577 // Charmed stop charming
11578 if (GetTypeId() == TYPEID_PLAYER)
11579 {
11582 }
11583
11584 // StopCastingCharm may remove a possessed pet?
11585 if (!IsInWorld())
11586 {
11587 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11588 return false;
11589 }
11590
11591 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11592 // prevent undefined behaviour
11593 if (aurApp && aurApp->GetRemoveMode())
11594 return false;
11595
11597 SetFaction(charmer->GetFaction());
11598
11599 // Pause any Idle movement
11600 PauseMovement(0, 0, false);
11601
11602 // Remove any active voluntary movement
11604
11605 // Stop any remaining spline, if no involuntary movement is found
11606 auto criteria = [](MovementGenerator const* movement) -> bool
11607 {
11608 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11609 };
11610 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11611 StopMoving();
11612
11613 // Set charmed
11614 charmer->SetCharm(this, true);
11615
11616 if (Player* player = ToPlayer())
11617 {
11618 if (player->isAFK())
11619 player->ToggleAFK();
11620
11621 player->SetClientControl(this, false);
11622 }
11623
11624 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11625 // prevent undefined behaviour
11626 if (aurApp && aurApp->GetRemoveMode())
11627 {
11628 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11631 charmer->SetCharm(this, false);
11632 return false;
11633 }
11634
11635 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11636 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11637 {
11638 InitCharmInfo();
11639 if (type == CHARM_TYPE_POSSESS)
11641 else
11643 }
11644
11645 if (playerCharmer)
11646 {
11647 switch (type)
11648 {
11649 case CHARM_TYPE_VEHICLE:
11651 playerCharmer->SetClientControl(this, true);
11652 playerCharmer->VehicleSpellInitialize();
11653 break;
11654 case CHARM_TYPE_POSSESS:
11657 playerCharmer->SetClientControl(this, true);
11658 playerCharmer->PossessSpellInitialize();
11660 break;
11661 case CHARM_TYPE_CHARM:
11662 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11663 {
11665 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11666 {
11667 // to prevent client crash
11669
11670 // just to enable stat window
11671 if (GetCharmInfo())
11672 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11673
11674 // if charmed two demons the same session, the 2nd gets the 1st one's name
11676 }
11677 }
11678 playerCharmer->CharmSpellInitialize();
11679 break;
11680 default:
11681 case CHARM_TYPE_CONVERT:
11682 break;
11683 }
11684 }
11685
11687
11688 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
11689 {
11690 // AI will schedule its own change if appropriate
11691 if (UnitAI* ai = GetAI())
11692 ai->OnCharmed(false);
11693 else
11695 }
11696 return true;
11697}
11698
11700{
11701 if (!IsCharmed())
11702 return;
11703
11704 if (charmer)
11705 ASSERT(charmer == GetCharmer());
11706 else
11707 charmer = GetCharmer();
11708
11709 ASSERT(charmer);
11710
11711 CharmType type;
11713 type = CHARM_TYPE_POSSESS;
11714 else if (charmer->IsOnVehicle(this))
11715 type = CHARM_TYPE_VEHICLE;
11716 else
11717 type = CHARM_TYPE_CHARM;
11718
11719 CastStop();
11720 AttackStop();
11721
11722 if (_oldFactionId)
11723 {
11725 _oldFactionId = 0;
11726 }
11727 else
11729
11732
11733 // Vehicle should not attack its passenger after he exists the seat
11734 if (type != CHARM_TYPE_VEHICLE)
11735 LastCharmerGUID = charmer->GetGUID();
11736
11737 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11739
11740 charmer->SetCharm(this, false);
11742
11743 Player* playerCharmer = charmer->ToPlayer();
11744 if (playerCharmer)
11745 {
11746 switch (type)
11747 {
11748 case CHARM_TYPE_VEHICLE:
11749 playerCharmer->SetClientControl(this, false);
11750 playerCharmer->SetClientControl(charmer, true);
11752 break;
11753 case CHARM_TYPE_POSSESS:
11755 playerCharmer->SetClientControl(this, false);
11756 playerCharmer->SetClientControl(charmer, true);
11759 break;
11760 case CHARM_TYPE_CHARM:
11761 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11762 {
11764 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11765 {
11766 SetClass(uint8(cinfo->unit_class));
11767 if (GetCharmInfo())
11768 GetCharmInfo()->SetPetNumber(0, true);
11769 else
11770 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
11771 }
11772 }
11773 break;
11774 case CHARM_TYPE_CONVERT:
11775 break;
11776 }
11777 }
11778
11779 if (Player* player = ToPlayer())
11780 player->SetClientControl(this, true);
11781
11782 if (playerCharmer && this != charmer->GetFirstControlled())
11783 playerCharmer->SendRemoveControlBar();
11784
11785 // a guardian should always have charminfo
11786 if (!IsGuardian())
11788
11789 // reset confused movement for example
11791
11792 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
11793 {
11794 if (UnitAI* charmedAI = GetAI())
11795 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
11796 else
11798 }
11799}
11800
11802{
11804 {
11805 SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).front()->GetMiscValue());
11806 return;
11807 }
11808
11809 if (GetTypeId() == TYPEID_PLAYER)
11811 else
11812 {
11814 {
11815 if (Unit* owner = GetOwner())
11816 {
11817 SetFaction(owner->GetFaction());
11818 return;
11819 }
11820 }
11821
11822 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
11823 SetFaction(cinfo->faction);
11824 }
11825}
11826
11827bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading /*= false*/)
11828{
11829 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
11830 if (!vehInfo)
11831 return false;
11832
11833 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
11834 m_updateFlag.Vehicle = true;
11836
11837 if (!loading)
11839
11840 return true;
11841}
11842
11843void Unit::RemoveVehicleKit(bool onRemoveFromWorld /*= false*/)
11844{
11845 if (!m_vehicleKit)
11846 return;
11847
11848 if (!onRemoveFromWorld)
11850
11852 m_vehicleKit = nullptr;
11853
11854 m_updateFlag.Vehicle = false;
11855 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
11857}
11858
11859bool Unit::IsOnVehicle(Unit const* vehicle) const
11860{
11861 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
11862}
11863
11865{
11866 return m_vehicle ? m_vehicle->GetBase() : nullptr;
11867}
11868
11870{
11871 Unit* vehicleRoot = GetVehicleBase();
11872
11873 if (!vehicleRoot)
11874 return nullptr;
11875
11876 for (;;)
11877 {
11878 if (!vehicleRoot->GetVehicleBase())
11879 return vehicleRoot;
11880
11881 vehicleRoot = vehicleRoot->GetVehicleBase();
11882 }
11883}
11884
11886{
11887 if (Unit* veh = GetVehicleBase())
11888 if (Creature* c = veh->ToCreature())
11889 return c;
11890
11891 return nullptr;
11892}
11893
11895{
11896 if (GetVehicle())
11897 return GetVehicleBase()->GetGUID();
11898 if (GetTransport())
11899 return GetTransport()->GetTransportGUID();
11900
11901 return ObjectGuid::Empty;
11902}
11903
11905{
11906 if (Vehicle* veh = GetVehicle())
11907 return veh;
11908 return GetTransport();
11909}
11910
11911bool Unit::IsInPartyWith(Unit const* unit) const
11912{
11913 if (this == unit)
11914 return true;
11915
11916 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11917 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11918 if (u1 == u2)
11919 return true;
11920
11921 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11922 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
11923 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
11925 return true;
11926
11927 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11928}
11929
11930bool Unit::IsInRaidWith(Unit const* unit) const
11931{
11932 if (this == unit)
11933 return true;
11934
11935 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11936 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11937 if (u1 == u2)
11938 return true;
11939
11940 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11941 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
11942 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
11944 return true;
11945
11946 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11947}
11948
11949void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
11950{
11951 Unit* owner = GetCharmerOrOwnerOrSelf();
11952 Group* group = nullptr;
11953 if (owner->GetTypeId() == TYPEID_PLAYER)
11954 group = owner->ToPlayer()->GetGroup();
11955
11956 if (group)
11957 {
11958 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
11959
11960 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
11961 {
11962 Player* Target = itr->GetSource();
11963
11964 // IsHostileTo check duel and controlled by enemy
11965 if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
11966 {
11967 if (Target->IsAlive())
11968 TagUnitMap.push_back(Target);
11969
11970 if (Guardian* pet = Target->GetGuardianPet())
11971 if (pet->IsAlive())
11972 TagUnitMap.push_back(pet);
11973 }
11974 }
11975 }
11976 else
11977 {
11978 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
11979 TagUnitMap.push_back(owner);
11980 if (Guardian* pet = owner->GetGuardianPet())
11981 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
11982 TagUnitMap.push_back(pet);
11983 }
11984}
11985
11987{
11988 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
11989 return entry->IsContestedGuardFaction();
11990
11991 return false;
11992}
11993
11994void Unit::SetPvP(bool state)
11995{
11996 if (state)
11998 else
12000}
12001
12002Aura* Unit::AddAura(uint32 spellId, Unit* target)
12003{
12004 if (!target)
12005 return nullptr;
12006
12007 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
12008 if (!spellInfo)
12009 return nullptr;
12010
12011 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
12012}
12013
12014Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
12015{
12016 if (!spellInfo)
12017 return nullptr;
12018
12019 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
12020 return nullptr;
12021
12022 if (target->IsImmunedToSpell(spellInfo, this))
12023 return nullptr;
12024
12025 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
12026 {
12027 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
12028 continue;
12029
12030 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
12031 effMask &= ~(1 << spellEffectInfo.EffectIndex);
12032 }
12033
12034 if (!effMask)
12035 return nullptr;
12036
12037 ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>());
12038 AuraCreateInfo createInfo(castId, spellInfo, GetMap()->GetDifficultyID(), effMask, target);
12039 createInfo.SetCaster(this);
12040
12041 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
12042 {
12043 aura->ApplyForTargets();
12044 return aura;
12045 }
12046 return nullptr;
12047}
12048
12049void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
12050{
12051 Aura* aura = target->GetAura(spellId, GetGUID());
12052 if (!aura)
12053 aura = AddAura(spellId, target);
12054 if (aura && stack)
12055 aura->SetStackAmount(stack);
12056}
12057
12058void Unit::SendPlaySpellVisual(Unit* target, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12059{
12061 playSpellVisual.Source = GetGUID();
12062 playSpellVisual.Target = target->GetGUID();
12063 playSpellVisual.TargetPosition = target->GetPosition();
12064 playSpellVisual.SpellVisualID = spellVisualId;
12065 playSpellVisual.TravelSpeed = travelSpeed;
12066 playSpellVisual.MissReason = missReason;
12067 playSpellVisual.ReflectStatus = reflectStatus;
12068 playSpellVisual.SpeedAsTime = speedAsTime;
12069 playSpellVisual.LaunchDelay = launchDelay;
12070 SendMessageToSet(playSpellVisual.Write(), true);
12071}
12072
12073void Unit::SendPlaySpellVisual(Position const& targetPosition, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12074{
12076 playSpellVisual.Source = GetGUID();
12077 playSpellVisual.TargetPosition = targetPosition;
12078 playSpellVisual.SpellVisualID = spellVisualId;
12079 playSpellVisual.TravelSpeed = travelSpeed;
12080 playSpellVisual.MissReason = missReason;
12081 playSpellVisual.ReflectStatus = reflectStatus;
12082 playSpellVisual.SpeedAsTime = speedAsTime;
12083 playSpellVisual.LaunchDelay = launchDelay;
12084 SendMessageToSet(playSpellVisual.Write(), true);
12085}
12086
12088{
12090 cancelSpellVisual.Source = GetGUID();
12091 cancelSpellVisual.SpellVisualID = id;
12092 SendMessageToSet(cancelSpellVisual.Write(), true);
12093}
12094
12095void Unit::SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
12096{
12098 playSpellVisualKit.Unit = GetGUID();
12099 playSpellVisualKit.KitRecID = id;
12100 playSpellVisualKit.KitType = type;
12101 playSpellVisualKit.Duration = duration;
12102 SendMessageToSet(playSpellVisualKit.Write(), true);
12103}
12104
12106{
12107 WorldPackets::Spells::CancelSpellVisualKit cancelSpellVisualKit;
12108 cancelSpellVisualKit.Source = GetGUID();
12109 cancelSpellVisualKit.SpellVisualKitID = id;
12110 SendMessageToSet(cancelSpellVisualKit.Write(), true);
12111}
12112
12113void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/, bool abortSpell /*= false*/)
12114{
12115 bool hasMissile = false;
12116 if (abortSpell)
12117 {
12118 for (std::pair<uint64 const, BasicEvent*> const& itr : m_Events.GetEvents())
12119 {
12120 if (Spell const* spell = Spell::ExtractSpellFromEvent(itr.second))
12121 {
12122 if (spell->GetSpellInfo()->Id == spellId)
12123 {
12124 itr.second->ScheduleAbort();
12125 hasMissile = true;
12126 }
12127 }
12128 }
12129 }
12130 else
12131 hasMissile = true;
12132
12133 if (hasMissile)
12134 {
12136 packet.OwnerGUID = GetGUID();
12137 packet.SpellID = spellId;
12138 packet.Reverse = reverseMissile;
12139 SendMessageToSet(packet.Write(), false);
12140 }
12141}
12142
12144{
12145 return !IsVehicle() && GetOwnerGUID().IsPlayer();
12146}
12147
12148/*static*/ void Unit::ApplyResilience(Unit const* victim, int32* damage)
12149{
12150 // player mounted on multi-passenger mount is also classified as vehicle
12151 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
12152 return;
12153
12154 Unit const* target = nullptr;
12155 if (victim->GetTypeId() == TYPEID_PLAYER)
12156 target = victim;
12157 else // victim->GetTypeId() == TYPEID_UNIT
12158 {
12159 if (Unit* owner = victim->GetOwner())
12160 if (owner->GetTypeId() == TYPEID_PLAYER)
12161 target = owner;
12162 }
12163
12164 if (!target)
12165 return;
12166
12167 *damage -= target->GetDamageReduction(*damage);
12168}
12169
12170int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
12171{
12172 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
12173 if (npcCaster)
12175
12176 return damage;
12177}
12178
12179// Melee based spells can be miss, parry or dodge on this step
12180// Crit or block - determined on damage calculation phase! (and can be both in some time)
12181float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const
12182{
12183 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
12184 return 0.f;
12185
12186 //calculate miss chance
12187 float missChance = victim->GetUnitMissChance();
12188
12189 // melee attacks while dual wielding have +19% chance to miss
12191 missChance += 19.0f;
12192
12193 // Spellmod from SpellModOp::HitChance
12194 float resistMissChance = 100.0f;
12195 if (spellInfo)
12196 if (Player* modOwner = GetSpellModOwner())
12197 modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, resistMissChance);
12198
12199 missChance -= resistMissChance - 100.0f;
12200
12201 if (attType == RANGED_ATTACK)
12202 missChance -= m_modRangedHitChance;
12203 else
12204 missChance -= m_modMeleeHitChance;
12205
12206 // miss chance from auras after calculating skill based miss
12208 if (attType == RANGED_ATTACK)
12210 else
12212
12213 return std::max(missChance, 0.f);
12214}
12215
12217{
12218}
12219
12221{
12222 if (!forced)
12224 else
12225 {
12227 // call MoveInLineOfSight for nearby creatures
12228 Trinity::AIRelocationNotifier notifier(*this);
12229 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
12230 }
12231}
12232
12233void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
12234{
12236 moveKnockBack.MoverGUID = GetGUID();
12237 moveKnockBack.SequenceIndex = m_movementCounter++;
12238 moveKnockBack.Speeds.HorzSpeed = speedXY;
12239 moveKnockBack.Speeds.VertSpeed = speedZ;
12240 moveKnockBack.Direction = Position(vcos, vsin);
12241 player->GetSession()->SendPacket(moveKnockBack.Write());
12242}
12243
12244void Unit::KnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
12245{
12246 Player* player = ToPlayer();
12247 if (!player)
12248 {
12249 if (Unit* charmer = GetCharmer())
12250 {
12251 player = charmer->ToPlayer();
12252 if (player && player->GetUnitBeingMoved() != this)
12253 player = nullptr;
12254 }
12255 }
12256
12257 if (!player)
12258 GetMotionMaster()->MoveKnockbackFrom(origin, speedXY, speedZ, spellEffectExtraData);
12259 else
12260 {
12261 float o = GetPosition() == origin ? GetOrientation() + M_PI : origin.GetAbsoluteAngle(this);
12262 if (speedXY < 0)
12263 {
12264 speedXY = -speedXY;
12265 o = o - M_PI;
12266 }
12267
12268 float vcos = std::cos(o);
12269 float vsin = std::sin(o);
12270 SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
12271 }
12272}
12273
12275{
12276 if (Player const* player = ToPlayer())
12277 return player->GetRatingBonusValue(cr);
12278 // Player's pet get resilience from owner
12279 else if (IsPet() && GetOwner())
12280 if (Player* owner = GetOwner()->ToPlayer())
12281 return owner->GetRatingBonusValue(cr);
12282
12283 return 0.0f;
12284}
12285
12286uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
12287{
12288 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
12289 return CalculatePct(damage, percent);
12290}
12291
12293{
12294 // Hardcoded cases
12295 switch (spellId)
12296 {
12297 case 7090: // Bear Form
12298 return 29414;
12299 case 35200: // Roc Form
12300 return 4877;
12301 case 24858: // Moonkin Form
12302 {
12303 if (HasAura(114301)) // Glyph of Stars
12304 return 0;
12305 break;
12306 }
12307 default:
12308 break;
12309 }
12310
12311 if (Player const* player = ToPlayer())
12312 {
12314 if (Item* artifact = player->GetItemByGuid(artifactAura->GetCastItemGUID()))
12315 if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)))
12316 if (ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID) == form)
12317 return artifactAppearance->OverrideShapeshiftDisplayID;
12318
12319 if (ShapeshiftFormModelData const* formModelData = sDB2Manager.GetShapeshiftFormModelData(GetRace(), player->GetNativeGender(), form))
12320 {
12321 bool useRandom = false;
12322 switch (form)
12323 {
12324 case FORM_CAT_FORM: useRandom = HasAura(210333); break; // Glyph of the Feral Chameleon
12325 case FORM_TRAVEL_FORM: useRandom = HasAura(344336); break; // Glyph of the Swift Chameleon
12326 case FORM_AQUATIC_FORM: useRandom = HasAura(344338); break; // Glyph of the Aquatic Chameleon
12328 case FORM_BEAR_FORM: useRandom = HasAura(107059); break; // Glyph of the Ursol Chameleon
12330 case FORM_FLIGHT_FORM: useRandom = HasAura(344342); break; // Glyph of the Aerial Chameleon
12331 default:
12332 break;
12333 }
12334
12335 if (useRandom)
12336 {
12337 std::vector<uint32> displayIds;
12338 displayIds.reserve(formModelData->Choices->size());
12339
12340 for (std::size_t i = 0; i < formModelData->Choices->size(); ++i)
12341 {
12342 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[i])
12343 {
12344 ChrCustomizationReqEntry const* choiceReq = sChrCustomizationReqStore.LookupEntry((*formModelData->Choices)[i]->ChrCustomizationReqID);
12345 if (!choiceReq || player->GetSession()->MeetsChrCustomizationReq(choiceReq, Races(GetRace()), Classes(GetClass()), false,
12346 MakeChrCustomizationChoiceRange(player->m_playerData->Customizations)))
12347 displayIds.push_back(displayInfo->DisplayID);
12348 }
12349 }
12350
12351 if (!displayIds.empty())
12353 }
12354 else
12355 {
12356 if (uint32 formChoice = player->GetCustomizationChoice(formModelData->OptionID))
12357 {
12358 auto choiceItr = std::find_if(formModelData->Choices->begin(), formModelData->Choices->end(), [formChoice](ChrCustomizationChoiceEntry const* choice)
12359 {
12360 return choice->ID == formChoice;
12361 });
12362
12363 if (choiceItr != formModelData->Choices->end())
12364 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[std::distance(formModelData->Choices->begin(), choiceItr)])
12365 return displayInfo->DisplayID;
12366 }
12367 }
12368 }
12369 switch (form)
12370 {
12371 case FORM_GHOST_WOLF:
12372 {
12373 if (HasAura(58135)) // Glyph of Spectral Wolf
12374 return 60247;
12375 break;
12376 }
12377 default:
12378 break;
12379 }
12380 }
12381
12382 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
12383 if (formEntry && formEntry->CreatureDisplayID)
12384 return formEntry->CreatureDisplayID;
12385
12386 return 0;
12387}
12388
12389void Unit::JumpTo(float speedXY, float speedZ, float angle, Optional<Position> dest)
12390{
12391 if (dest)
12392 angle += GetRelativeAngle(*dest);
12393
12394 if (GetTypeId() == TYPEID_UNIT)
12395 GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ);
12396 else
12397 {
12398 float vcos = std::cos(angle+GetOrientation());
12399 float vsin = std::sin(angle+GetOrientation());
12400 SendMoveKnockBack(ToPlayer(), speedXY, -speedZ, vcos, vsin);
12401 }
12402}
12403
12404void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12405{
12406 bool spellClickHandled = false;
12407 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12409
12410 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12411 for (auto const& clickPair : clickBounds)
12412 {
12414 if (!clickPair.second.IsFitToRequirements(clicker, this))
12415 continue;
12416
12418 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12419 continue;
12420
12421 spellClickHandled = HandleSpellClick(clicker, seatId, clickPair.second.spellId, flags, &clickPair.second);
12422
12423 // if (!spellEntry) should be checked at npc_spellclick load
12424 }
12425
12426 Creature* creature = ToCreature();
12427 if (creature && creature->IsAIEnabled())
12428 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12429}
12430
12431bool Unit::HandleSpellClick(Unit* clicker, int8 seatId, uint32 spellId, TriggerCastFlags flags /*= TRIGGERED_NONE*/, SpellClickInfo const* spellClickInfo /*= nullptr*/)
12432{
12433 Unit* caster = clicker;
12434 Unit* target = this;
12435 ObjectGuid origCasterGUID = caster->GetGUID();
12437
12438 if (spellClickInfo)
12439 {
12440 caster = (spellClickInfo->castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12441 target = (spellClickInfo->castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12442 origCasterGUID = (spellClickInfo->castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12443 }
12444
12445 if (!spellId)
12446 {
12447 TC_LOG_ERROR("sql.sql", "No valid spell specified for clickee {} and clicker {}!", target->GetGUID(), caster->GetGUID());
12448 return false;
12449 }
12450
12451 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(spellId, caster->GetMap()->GetDifficultyID());
12452
12453 uint8 effectIndex = 0;
12454 bool hasControlVehicleAura = false;
12455 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12456 {
12457 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12458 {
12459 hasControlVehicleAura = true;
12460 break;
12461 }
12462 ++effectIndex;
12463 }
12464
12465 if (seatId > -1)
12466 {
12467 if (!hasControlVehicleAura)
12468 {
12469 if (!spellClickInfo)
12470 TC_LOG_ERROR("sql.sql", "RideSpell {} specified in vehicle_accessory or vehicle_template_accessory is not a valid vehicle enter aura!", spellId);
12471 else
12472 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", spellId);
12473 return false;
12474 }
12475
12476 if (IsInMap(caster))
12477 {
12479 args.OriginalCaster = origCasterGUID;
12480 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + effectIndex), seatId + 1);
12481 castResult = caster->CastSpell(target, spellId, args);
12482 }
12483 else // This can happen during Player::_LoadAuras
12484 {
12485 int32 bp[MAX_SPELL_EFFECTS] = { };
12486 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12487 bp[spellEffectInfo.EffectIndex] = int32(spellEffectInfo.BasePoints);
12488
12489 bp[effectIndex] = seatId;
12490
12491 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12492 createInfo
12493 .SetCaster(clicker)
12494 .SetBaseAmount(bp)
12495 .SetCasterGUID(origCasterGUID);
12496
12498 }
12499 }
12500 else
12501 {
12502 if (IsInMap(caster))
12503 castResult = caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12504 else
12505 {
12506 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12507 createInfo
12508 .SetCaster(clicker)
12509 .SetCasterGUID(origCasterGUID);
12510
12512 }
12513 }
12514 return castResult == SPELL_FAILED_SUCCESS;
12515}
12516
12517void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12518{
12520 args.AddSpellMod(SPELLVALUE_BASE_POINT0, seatId + 1);
12522}
12523
12524void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12525{
12526 // Must be called only from aura handler
12527 ASSERT(aurApp);
12528
12529 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12530 return;
12531
12532 if (m_vehicle)
12533 {
12534 if (m_vehicle != vehicle)
12535 {
12536 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12537 ExitVehicle();
12538 }
12539 else if (seatId >= 0 && seatId == GetTransSeat())
12540 return;
12541 else
12542 {
12543 //Exit the current vehicle because unit will reenter in a new seat.
12545 }
12546 }
12547
12548 if (aurApp->GetRemoveMode())
12549 return;
12550
12551 if (Player* player = ToPlayer())
12552 {
12553 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12554 {
12555 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12556 return;
12557 }
12558
12559 if (Creature* vehicleBaseCreature = vehicle->GetBase()->ToCreature())
12560 {
12561 // If a player entered a vehicle that is part of a formation, remove it from said formation
12562 if (CreatureGroup* creatureGroup = vehicleBaseCreature->GetFormation())
12563 FormationMgr::RemoveCreatureFromGroup(creatureGroup, vehicleBaseCreature);
12564 }
12565 }
12566
12567 ASSERT(!m_vehicle);
12568 (void)vehicle->AddVehiclePassenger(this, seatId);
12569}
12570
12571void Unit::ChangeSeat(int8 seatId, bool next)
12572{
12573 if (!m_vehicle)
12574 return;
12575
12576 // Don't change if current and new seat are identical
12577 if (seatId == GetTransSeat())
12578 return;
12579
12580 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12581 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12582 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12583 return;
12584
12585 AuraEffect* rideVehicleEffect = nullptr;
12587 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12588 {
12589 if ((*itr)->GetCasterGUID() != GetGUID())
12590 continue;
12591
12592 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12593 ASSERT(!rideVehicleEffect);
12594 rideVehicleEffect = *itr;
12595 }
12596
12597 // Unit riding a vehicle must always have control vehicle aura on target
12598 ASSERT(rideVehicleEffect);
12599
12600 rideVehicleEffect->ChangeAmount(seat->first + 1);
12601}
12602
12603void Unit::ExitVehicle(Position const* /*exitPosition*/)
12604{
12606 if (!m_vehicle)
12607 return;
12608
12613 /*_ExitVehicle(exitPosition);*/
12620}
12621
12622void Unit::_ExitVehicle(Position const* exitPosition)
12623{
12627 if (!m_vehicle)
12628 return;
12629
12630 // This should be done before dismiss, because there may be some aura removal
12632 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12633
12634 if (!vehicle)
12635 {
12636 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12637 return;
12638 }
12639
12640 Player* player = ToPlayer();
12641
12642 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12643 if (player && player->duel && player->duel->IsMounted)
12644 player->DuelComplete(DUEL_FLED);
12645
12646 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12647
12649
12650 if (player)
12651 player->SetFallInformation(0, GetPositionZ());
12652
12653 Position pos;
12654 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12655 if (exitPosition)
12656 pos = *exitPosition;
12657 else
12658 {
12659 // Set exit position to vehicle position and use the current orientation
12660 pos = vehicle->GetBase()->GetPosition();
12662
12663 // Change exit position based on seat entry addon data
12664 if (seatAddon)
12665 {
12667 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12669 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12670 }
12671 }
12672
12673 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
12674 {
12675 float height = pos.GetPositionZ() + vehicleCollisionHeight;
12676
12677 // Creatures without inhabit type air should begin falling after exiting the vehicle
12678 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
12679 init.SetFall();
12680
12681 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
12682 init.SetFacing(pos.GetOrientation());
12683 init.SetTransportExit();
12684 };
12686
12687 if (player)
12689
12690 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12691 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
12692 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
12693
12695 {
12696 // Vehicle just died, we die too
12697 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
12699 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
12700 else
12701 ToTempSummon()->UnSummon(2000); // Approximation
12702 }
12703
12705}
12706
12708{
12710}
12711
12712bool Unit::CanSwim() const
12713{
12714 // 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
12716 return false;
12717 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
12718 return true;
12720 return false;
12722 return true;
12724}
12725
12726void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
12727{
12728 DisableSpline();
12729 TeleportLocation target{ .Location = { GetMapId(), pos } };
12730 if (GetTypeId() == TYPEID_PLAYER)
12732 else
12733 {
12734 SendTeleportPacket(target);
12735 UpdatePosition(pos, true);
12737 }
12738}
12739
12740void Unit::SendTeleportPacket(TeleportLocation const& teleportLocation)
12741{
12742 // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
12743 // SMSG_MOVE_TELEPORT is sent to self in order to trigger CMSG_MOVE_TELEPORT_ACK and update the position server side
12744
12746 moveUpdateTeleport.Status = &m_movementInfo;
12747 if (_movementForces)
12748 moveUpdateTeleport.MovementForces = _movementForces->GetForces();
12749 Unit* broadcastSource = this;
12750
12751 // should this really be the unit _being_ moved? not the unit doing the moving?
12752 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12753 {
12755 moveTeleport.MoverGUID = GetGUID();
12756 moveTeleport.Pos = teleportLocation.Location;
12757 moveTeleport.TransportGUID = teleportLocation.TransportGuid;
12758 moveTeleport.Facing = teleportLocation.Location.GetOrientation();
12759 moveTeleport.SequenceIndex = m_movementCounter++;
12760 playerMover->SendDirectMessage(moveTeleport.Write());
12761
12762 broadcastSource = playerMover;
12763 }
12764 else
12765 {
12766 // This is the only packet sent for creatures which contains MovementInfo structure
12767 // we do not update m_movementInfo for creatures so it needs to be done manually here
12768 moveUpdateTeleport.Status->guid = GetGUID();
12769 moveUpdateTeleport.Status->time = getMSTime();
12770
12771 if (teleportLocation.TransportGuid)
12772 {
12773 Transport* transport = GetMap()->GetTransport(*teleportLocation.TransportGuid);
12774 if (!transport)
12775 return;
12776
12777 float x, y, z, o;
12778 teleportLocation.Location.GetPosition(x, y, z, o);
12779 transport->CalculatePassengerPosition(x, y, z, &o);
12780 moveUpdateTeleport.Status->pos.Relocate(x, y, z, o);
12781 moveUpdateTeleport.Status->transport.pos.Relocate(teleportLocation.Location);
12782 }
12783 else
12784 moveUpdateTeleport.Status->pos.Relocate(teleportLocation.Location);
12785 }
12786
12787 // Broadcast the packet to everyone except self.
12788 broadcastSource->SendMessageToSet(moveUpdateTeleport.Write(), false);
12789}
12790
12791bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
12792{
12793 // prevent crash when a bad coord is sent by the client
12794 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
12795 {
12796 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
12797 return false;
12798 }
12799
12800 // Check if angular distance changed
12801 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
12802
12803 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
12804 bool const relocated = (teleport ||
12805 std::fabs(GetPositionX() - x) > 0.001f ||
12806 std::fabs(GetPositionY() - y) > 0.001f ||
12807 std::fabs(GetPositionZ() - z) > 0.001f);
12808
12809 if (relocated)
12810 {
12811 // move and update visible state if need
12812 if (GetTypeId() == TYPEID_PLAYER)
12813 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
12814 else
12815 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
12816
12818 for (AuraEffect const* auraEffect : controlZoneAuras)
12819 if (GameObject* controlZone = GetGameObject(auraEffect->GetSpellInfo()->Id))
12820 GetMap()->GameObjectRelocation(controlZone, x, y, z, orientation);
12821 }
12822 else if (turn)
12823 UpdateOrientation(orientation);
12824
12825 _positionUpdateInfo.Relocated = relocated;
12827
12828 if (IsFalling())
12830
12831 bool isInWater = IsInWater();
12832 if (!IsFalling() || isInWater || IsFlying())
12834
12835 if (isInWater)
12837
12838 return (relocated || turn);
12839}
12840
12841bool Unit::UpdatePosition(Position const& pos, bool teleport)
12842{
12843 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
12844}
12845
12847void Unit::UpdateOrientation(float orientation)
12848{
12849 SetOrientation(orientation);
12850 if (IsVehicle())
12852}
12853
12855void Unit::UpdateHeight(float newZ)
12856{
12858 if (IsVehicle())
12860}
12861
12862// baseRage means damage taken when attacker = false
12864{
12865 float addRage = baseRage;
12866
12867 // talent who gave more rage on attack
12869
12870 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
12871
12872 return ModifyPower(POWER_RAGE, uint32(addRage * 10), false);
12873}
12874
12876{
12877 if (Unit* victim = GetVictim())
12878 {
12879 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
12880 {
12881 AttackStop();
12882 if (IsNonMeleeSpellCast(false))
12884
12885 // melee and ranged forced attack cancel
12886 if (GetTypeId() == TYPEID_PLAYER)
12888 }
12889 }
12890
12891 AttackerSet const& attackers = getAttackers();
12892 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
12893 {
12894 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
12895 {
12896 (*itr)->AttackStop();
12897 itr = attackers.begin();
12898 }
12899 else
12900 ++itr;
12901 }
12902
12903 std::vector<CombatReference*> refsToEnd;
12904 for (auto const& pair : m_combatManager.GetPvECombatRefs())
12905 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
12906 refsToEnd.push_back(pair.second);
12907 for (CombatReference* ref : refsToEnd)
12908 ref->EndCombat();
12909
12910 for (Unit* minion : m_Controlled)
12911 minion->StopAttackFaction(faction_id);
12912}
12913
12915{
12916 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
12917 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
12918 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
12919 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
12920 if (IsInWorld())
12921 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
12922
12923 std::ostringstream o;
12924 o << "Summon Slot: ";
12925 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
12926 o << m_SummonSlot[i].ToString() << ", ";
12927
12928 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12929 o.str("");
12930
12931 o << "Controlled List: ";
12932 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
12933 o << (*itr)->GetGUID().ToString() << ", ";
12934 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12935 o.str("");
12936
12937 o << "Aura List: ";
12938 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
12939 o << itr->first << ", ";
12940 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12941 o.str("");
12942
12943 if (IsVehicle())
12944 {
12945 o << "Passenger List: ";
12946 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
12947 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
12948 o << passenger->GetGUID().ToString() << ", ";
12949 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12950 }
12951
12952 if (GetVehicle())
12953 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
12954}
12955
12957{
12959 breakTarget.UnitGUID = GetGUID();
12960 SendMessageToSet(breakTarget.Write(), false);
12961}
12962
12964{
12965 Optional<int32> resist;
12966 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
12967 {
12968 int32 schoolResistance = GetResistance(SpellSchools(i));
12969 if (mask & (1 << i) && (!resist || *resist > schoolResistance))
12970 resist = schoolResistance;
12971 }
12972
12973 return resist.value_or(0);
12974}
12975
12977{
12978 _isCommandAttack = val;
12979}
12980
12982{
12983 return _isCommandAttack;
12984}
12985
12987{
12988 _isCommandFollow = val;
12989}
12990
12992{
12993 return _isCommandFollow;
12994}
12995
12997{
12999 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
13000
13001 if (_unit->movespline->onTransport)
13002 if (TransportBase* transport = _unit->GetDirectTransport())
13003 transport->CalculatePassengerPosition(stayPos.x, stayPos.y, stayPos.z);
13004
13005 _stayX = stayPos.x;
13006 _stayY = stayPos.y;
13007 _stayZ = stayPos.z;
13008}
13009
13010void CharmInfo::GetStayPosition(float &x, float &y, float &z)
13011{
13012 x = _stayX;
13013 y = _stayY;
13014 z = _stayZ;
13015}
13016
13018{
13019 _isAtStay = val;
13020}
13021
13023{
13024 return _isAtStay;
13025}
13026
13028{
13029 _isFollowing = val;
13030}
13031
13033{
13034 return _isFollowing;
13035}
13036
13038{
13039 _isReturning = val;
13040}
13041
13043{
13044 return _isReturning;
13045}
13046
13048{
13051}
13052
13053void Unit::SetFacingTo(float ori, bool force)
13054{
13055 // do not face when already moving
13056 if (!force && (!IsStopped() || !movespline->Finalized()))
13057 return;
13058
13059 Movement::MoveSplineInit init(this);
13060 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13061 if (GetTransport())
13062 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
13063 init.SetFacing(ori);
13064
13065 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13067 if (Creature* creature = ToCreature())
13068 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13069}
13070
13071void Unit::SetFacingToObject(WorldObject const* object, bool force)
13072{
13073 // do not face when already moving
13074 if (!force && (!IsStopped() || !movespline->Finalized()))
13075 return;
13076
13078 Movement::MoveSplineInit init(this);
13079 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13080 init.SetFacing(GetAbsoluteAngle(object)); // when on transport, GetAbsoluteAngle will still return global coordinates (and angle) that needs transforming
13081
13082 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13084 if (Creature* creature = ToCreature())
13085 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13086}
13087
13088void Unit::SetFacingToPoint(Position const& point, bool force)
13089{
13090 // do not face when already moving
13091 if (!force && (!IsStopped() || !movespline->Finalized()))
13092 return;
13093
13095 Movement::MoveSplineInit init(this);
13096 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13097 if (GetTransport())
13098 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
13099 init.SetFacing(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
13100
13101 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13103 if (Creature* creature = ToCreature())
13104 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13105}
13106
13107bool Unit::SetWalk(bool enable)
13108{
13109 if (enable == IsWalking())
13110 return false;
13111
13112 if (enable)
13114 else
13116
13118
13119 WorldPackets::Movement::MoveSplineSetFlag packet(walkModeTable[enable]);
13120 packet.MoverGUID = GetGUID();
13121 SendMessageToSet(packet.Write(), true);
13122 return true;
13123}
13124
13125bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/)
13126{
13127 if (disable == IsGravityDisabled())
13128 return false;
13129
13130 if (disable)
13131 {
13134 }
13135 else
13137
13138 static OpcodeServer const gravityOpcodeTable[2][2] =
13139 {
13142 };
13143
13144 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13145 {
13146 WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]);
13147 packet.MoverGUID = GetGUID();
13149 playerMover->SendDirectMessage(packet.Write());
13150
13152 moveUpdate.Status = &m_movementInfo;
13153 SendMessageToSet(moveUpdate.Write(), playerMover);
13154 }
13155 else
13156 {
13157 WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]);
13158 packet.MoverGUID = GetGUID();
13159 SendMessageToSet(packet.Write(), true);
13160 }
13161
13162 if (IsAlive())
13163 {
13164 if (IsGravityDisabled() || IsHovering())
13165 SetPlayHoverAnim(true);
13166 else
13167 SetPlayHoverAnim(false);
13168 }
13169 else if (IsPlayer()) // To update player who dies while flying/hovering
13170 SetPlayHoverAnim(false, false);
13171
13172 if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
13173 {
13174 if (IsGravityDisabled())
13176 else if (IsHovering())
13178 else
13180 }
13181
13182 return true;
13183}
13184
13185bool Unit::SetFall(bool enable)
13186{
13188 return false;
13189
13190 if (enable)
13191 {
13194 }
13195 else
13197
13198 return true;
13199}
13200
13201bool Unit::SetSwim(bool enable)
13202{
13204 return false;
13205
13206 if (enable)
13208 else
13210
13211 static OpcodeServer const swimOpcodeTable[2] = { SMSG_MOVE_SPLINE_STOP_SWIM, SMSG_MOVE_SPLINE_START_SWIM};
13212
13213 WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]);
13214 packet.MoverGUID = GetGUID();
13215 SendMessageToSet(packet.Write(), true);
13216
13217 return true;
13218}
13219
13220bool Unit::SetCanFly(bool enable)
13221{
13223 return false;
13224
13225 if (enable)
13226 {
13229 }
13230 else
13232
13233 static OpcodeServer const flyOpcodeTable[2][2] =
13234 {
13237 };
13238
13239 if (!enable && GetTypeId() == TYPEID_PLAYER)
13241
13242 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13243 {
13244 WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]);
13245 packet.MoverGUID = GetGUID();
13247 playerMover->SendDirectMessage(packet.Write());
13248
13250 moveUpdate.Status = &m_movementInfo;
13251 SendMessageToSet(moveUpdate.Write(), playerMover);
13252 }
13253 else
13254 {
13255 WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]);
13256 packet.MoverGUID = GetGUID();
13257 SendMessageToSet(packet.Write(), true);
13258 }
13259
13260 return true;
13261}
13262
13263bool Unit::SetWaterWalking(bool enable)
13264{
13266 return false;
13267
13268 if (enable)
13270 else
13272
13273 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
13274 {
13277 };
13278
13279 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13280 {
13281 WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]);
13282 packet.MoverGUID = GetGUID();
13284 playerMover->SendDirectMessage(packet.Write());
13285
13287 moveUpdate.Status = &m_movementInfo;
13288 SendMessageToSet(moveUpdate.Write(), playerMover);
13289 }
13290 else
13291 {
13292 WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]);
13293 packet.MoverGUID = GetGUID();
13294 SendMessageToSet(packet.Write(), true);
13295 }
13296
13297 return true;
13298}
13299
13300bool Unit::SetFeatherFall(bool enable)
13301{
13302 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13303 //if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW))
13304 // return false;
13305
13306 if (enable)
13308 else
13310
13311 static OpcodeServer const featherFallOpcodeTable[2][2] =
13312 {
13315 };
13316
13317 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13318 {
13319 WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]);
13320 packet.MoverGUID = GetGUID();
13322 playerMover->SendDirectMessage(packet.Write());
13323
13325 moveUpdate.Status = &m_movementInfo;
13326 SendMessageToSet(moveUpdate.Write(), playerMover);
13327 }
13328 else
13329 {
13330 WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]);
13331 packet.MoverGUID = GetGUID();
13332 SendMessageToSet(packet.Write(), true);
13333 }
13334
13335 return true;
13336}
13337
13338bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
13339{
13341 return false;
13342
13343 float hoverHeight = m_unitData->HoverHeight;
13344
13345 if (enable)
13346 {
13349 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
13350 UpdateHeight(GetPositionZ() + hoverHeight);
13351 }
13352 else
13353 {
13356 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
13357 {
13358 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
13360 UpdateHeight(newZ);
13361 }
13362 }
13363
13364 static OpcodeServer const hoverOpcodeTable[2][2] =
13365 {
13368 };
13369
13370 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13371 {
13372 WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]);
13373 packet.MoverGUID = GetGUID();
13375 playerMover->SendDirectMessage(packet.Write());
13376
13378 moveUpdate.Status = &m_movementInfo;
13379 SendMessageToSet(moveUpdate.Write(), playerMover);
13380 }
13381 else
13382 {
13383 WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]);
13384 packet.MoverGUID = GetGUID();
13385 SendMessageToSet(packet.Write(), true);
13386 }
13387
13388 if (IsAlive())
13389 {
13390 if (IsGravityDisabled() || IsHovering())
13391 SetPlayHoverAnim(true);
13392 else
13393 SetPlayHoverAnim(false);
13394 }
13395 else if (IsPlayer()) // To update player who dies while flying/hovering
13396 SetPlayHoverAnim(false, false);
13397
13398 if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
13399 {
13400 if (IsGravityDisabled())
13402 else if (IsHovering())
13404 else
13406 }
13407
13408 return true;
13409}
13410
13411bool Unit::SetCollision(bool disable)
13412{
13414 return false;
13415
13416 if (disable)
13418 else
13420
13421 static OpcodeServer const collisionOpcodeTable[2][2] =
13422 {
13425 };
13426
13427 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13428 {
13429 WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]);
13430 packet.MoverGUID = GetGUID();
13432 playerMover->SendDirectMessage(packet.Write());
13433
13435 moveUpdate.Status = &m_movementInfo;
13436 SendMessageToSet(moveUpdate.Write(), playerMover);
13437 }
13438 else
13439 {
13440 WorldPackets::Movement::MoveSplineSetFlag packet(collisionOpcodeTable[disable][0]);
13441 packet.MoverGUID = GetGUID();
13442 SendMessageToSet(packet.Write(), true);
13443 }
13444
13445 return true;
13446}
13447
13449{
13450 if (GetTypeId() != TYPEID_PLAYER)
13451 return false;
13452
13454 return false;
13455
13456 if (enable)
13458 else
13460
13461 static constexpr OpcodeServer fullSpeedTurningOpcodeTable[2] =
13462 {
13465 };
13466
13467 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13468 {
13469 WorldPackets::Movement::MoveSetFlag packet(fullSpeedTurningOpcodeTable[enable]);
13470 packet.MoverGUID = GetGUID();
13472 playerMover->SendDirectMessage(packet.Write());
13473
13475 moveUpdate.Status = &m_movementInfo;
13476 SendMessageToSet(moveUpdate.Write(), playerMover);
13477 }
13478
13479 return true;
13480}
13481
13483{
13484 if (GetTypeId() != TYPEID_PLAYER)
13485 return false;
13486
13488 return false;
13489
13490 if (enable)
13492 else
13494
13495 static OpcodeServer const swimToFlyTransOpcodeTable[2] =
13496 {
13499 };
13500
13501 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13502 {
13503 WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]);
13504 packet.MoverGUID = GetGUID();
13506 playerMover->SendDirectMessage(packet.Write());
13507
13509 moveUpdate.Status = &m_movementInfo;
13510 SendMessageToSet(moveUpdate.Write(), playerMover);
13511 }
13512
13513 return true;
13514}
13515
13517{
13518 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13519 //if (enable == HasExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING))
13520 // return false;
13521
13522 if (enable)
13524 else
13526
13527 static OpcodeServer const canTurnWhileFallingOpcodeTable[2] =
13528 {
13531 };
13532
13533 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13534 {
13535 WorldPackets::Movement::MoveSetFlag packet(canTurnWhileFallingOpcodeTable[enable]);
13536 packet.MoverGUID = GetGUID();
13538 playerMover->SendDirectMessage(packet.Write());
13539
13541 moveUpdate.Status = &m_movementInfo;
13542 SendMessageToSet(moveUpdate.Write(), playerMover);
13543 }
13544
13545 return true;
13546}
13547
13548bool Unit::SetCanDoubleJump(bool enable)
13549{
13551 return false;
13552
13553 if (enable)
13555 else
13557
13558 static OpcodeServer const doubleJumpOpcodeTable[2] =
13559 {
13562 };
13563
13564 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13565 {
13566 WorldPackets::Movement::MoveSetFlag packet(doubleJumpOpcodeTable[enable]);
13567 packet.MoverGUID = GetGUID();
13569 playerMover->SendDirectMessage(packet.Write());
13570
13572 moveUpdate.Status = &m_movementInfo;
13573 SendMessageToSet(moveUpdate.Write(), playerMover);
13574 }
13575
13576 return true;
13577}
13578
13579bool Unit::SetDisableInertia(bool disable)
13580{
13582 return false;
13583
13584 if (disable)
13586 else
13588
13589 static OpcodeServer const disableInertiaOpcodeTable[2] =
13590 {
13593 };
13594
13595 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13596 {
13597 WorldPackets::Movement::MoveSetFlag packet(disableInertiaOpcodeTable[disable]);
13598 packet.MoverGUID = GetGUID();
13600 playerMover->SendDirectMessage(packet.Write());
13601
13603 moveUpdate.Status = &m_movementInfo;
13604 SendMessageToSet(moveUpdate.Write(), playerMover);
13605 }
13606
13607 return true;
13608}
13609
13610bool Unit::SetCanAdvFly(bool enable)
13611{
13613 return false;
13614
13615 if (enable)
13617 else
13619
13620 static OpcodeServer const advFlyOpcodeTable[2] =
13621 {
13624 };
13625
13626 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13627 {
13628 WorldPackets::Movement::MoveSetFlag packet(advFlyOpcodeTable[enable]);
13629 packet.MoverGUID = GetGUID();
13631 playerMover->SendDirectMessage(packet.Write());
13632
13634 moveUpdate.Status = &m_movementInfo;
13635 SendMessageToSet(moveUpdate.Write(), playerMover);
13636 }
13637
13638 return true;
13639}
13640
13641bool Unit::SetMoveCantSwim(bool cantSwim)
13642{
13644 return false;
13645
13646 if (cantSwim)
13648 else
13650
13651 static OpcodeServer const cantSwimOpcodeTable[2] =
13652 {
13655 };
13656
13657 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13658 {
13659 WorldPackets::Movement::MoveSetFlag packet(cantSwimOpcodeTable[cantSwim]);
13660 packet.MoverGUID = GetGUID();
13662 playerMover->SendDirectMessage(packet.Write());
13663
13665 moveUpdate.Status = &m_movementInfo;
13666 SendMessageToSet(moveUpdate.Write(), playerMover);
13667 }
13668
13669 return true;
13670}
13671
13673{
13674 if (Player* player = ToPlayer())
13675 {
13677 moveSetVehicleRec.MoverGUID = GetGUID();
13678 moveSetVehicleRec.SequenceIndex = m_movementCounter++;
13679 moveSetVehicleRec.VehicleRecID = vehicleId;
13680 player->SendDirectMessage(moveSetVehicleRec.Write());
13681 }
13682
13684 setVehicleRec.VehicleGUID = GetGUID();
13685 setVehicleRec.VehicleRecID = vehicleId;
13686 SendMessageToSet(setVehicleRec.Write(), true);
13687}
13688
13689void Unit::ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction /*= {}*/, ObjectGuid transportGuid /*= ObjectGuid::Empty*/)
13690{
13691 if (!_movementForces)
13692 _movementForces = std::make_unique<MovementForces>();
13693
13694 MovementForce force;
13695 force.ID = id;
13696 force.Origin = origin;
13697 force.Direction = direction;
13698 if (transportGuid.IsMOTransport())
13699 force.TransportID = transportGuid.GetCounter();
13700
13701 force.Magnitude = magnitude;
13702 force.Type = type;
13703
13704 if (_movementForces->Add(force))
13705 {
13706 if (Player const* movingPlayer = GetPlayerMovingMe())
13707 {
13709 applyMovementForce.MoverGUID = GetGUID();
13710 applyMovementForce.SequenceIndex = m_movementCounter++;
13711 applyMovementForce.Force = &force;
13712 movingPlayer->SendDirectMessage(applyMovementForce.Write());
13713 }
13714 else
13715 {
13717 updateApplyMovementForce.Status = &m_movementInfo;
13718 updateApplyMovementForce.Force = &force;
13719 SendMessageToSet(updateApplyMovementForce.Write(), true);
13720 }
13721 }
13722}
13723
13725{
13726 if (!_movementForces)
13727 return;
13728
13729 if (_movementForces->Remove(id))
13730 {
13731 if (Player const* movingPlayer = GetPlayerMovingMe())
13732 {
13734 moveRemoveMovementForce.MoverGUID = GetGUID();
13735 moveRemoveMovementForce.SequenceIndex = m_movementCounter++;
13736 moveRemoveMovementForce.ID = id;
13737 movingPlayer->SendDirectMessage(moveRemoveMovementForce.Write());
13738 }
13739 else
13740 {
13742 updateRemoveMovementForce.Status = &m_movementInfo;
13743 updateRemoveMovementForce.TriggerGUID = id;
13744 SendMessageToSet(updateRemoveMovementForce.Write(), true);
13745 }
13746 }
13747
13748 if (_movementForces->IsEmpty())
13749 _movementForces.reset();
13750}
13751
13753{
13755 return false;
13756
13757 if (ignore)
13759 else
13761
13762 static OpcodeServer const ignoreMovementForcesOpcodeTable[2] =
13763 {
13766 };
13767
13768 if (Player const* movingPlayer = GetPlayerMovingMe())
13769 {
13770 WorldPackets::Movement::MoveSetFlag packet(ignoreMovementForcesOpcodeTable[ignore]);
13771 packet.MoverGUID = GetGUID();
13773 movingPlayer->SendDirectMessage(packet.Write());
13774
13776 moveUpdate.Status = &m_movementInfo;
13777 SendMessageToSet(moveUpdate.Write(), movingPlayer);
13778 }
13779
13780 return true;
13781}
13782
13784{
13786
13787 if (Player* movingPlayer = GetPlayerMovingMe())
13788 {
13790 setModMovementForceMagnitude.MoverGUID = GetGUID();
13791 setModMovementForceMagnitude.SequenceIndex = m_movementCounter++;
13792 setModMovementForceMagnitude.Speed = modMagnitude;
13793 movingPlayer->SendDirectMessage(setModMovementForceMagnitude.Write());
13794 ++movingPlayer->m_movementForceModMagnitudeChanges;
13795 }
13796 else
13797 {
13799 updateModMovementForceMagnitude.Status = &m_movementInfo;
13800 updateModMovementForceMagnitude.Speed = modMagnitude;
13801 SendMessageToSet(updateModMovementForceMagnitude.Write(), true);
13802 }
13803
13804 if (modMagnitude != 1.0f && !_movementForces)
13805 _movementForces = std::make_unique<MovementForces>();
13806
13807 if (_movementForces)
13808 {
13809 _movementForces->SetModMagnitude(modMagnitude);
13810 if (_movementForces->IsEmpty())
13811 _movementForces.reset();
13812 }
13813}
13814
13815void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
13816{
13817 if (IsPlayingHoverAnim() == enable)
13818 return;
13819
13820 _playHoverAnim = enable;
13821
13822 if (!sendUpdate)
13823 return;
13824
13826 data.UnitGUID = GetGUID();
13827 data.PlayHoverAnim = enable;
13828
13829 SendMessageToSet(data.Write(), true);
13830}
13831
13833{
13834 float hoverHeight = DEFAULT_PLAYER_HOVER_HEIGHT;
13835 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
13836
13837 uint32 displayId = IsMounted() ? GetMountDisplayId() : GetDisplayId();
13838
13839 // Get DisplayScale for creatures
13840 if (IsCreature())
13841 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
13842 displayScale = model->DisplayScale;
13843
13844 if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(displayId))
13845 if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelID))
13846 hoverHeight = modelData->HoverHeight * modelData->ModelScale * displayInfo->CreatureModelScale * displayScale;
13847
13848 SetHoverHeight(hoverHeight ? hoverHeight : DEFAULT_PLAYER_HOVER_HEIGHT);
13849}
13850
13852{
13853 return movespline->Initialized() && !movespline->Finalized();
13854}
13855
13857{
13859 if (target == this || GetOwnerGUID() == target->GetGUID())
13861
13865
13866 return flags;
13867}
13868
13870{
13871 if (Battleground* bg = target->GetBattleground())
13872 {
13873 if (bg->isArena())
13874 {
13876 destroyArenaUnit.Guid = GetGUID();
13877 target->GetSession()->SendPacket(destroyArenaUnit.Write());
13878 }
13879 }
13880
13882}
13883
13884void Unit::ClearUpdateMask(bool remove)
13885{
13888}
13889
13890int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
13891{
13892 int32 val = 0;
13893 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
13894 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
13895 {
13896 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
13897 {
13898 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
13899 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
13900 {
13901 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
13902 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
13903 {
13904 // absolute value only
13905 if (abs(val) < abs((*auraItr)->GetAmount()))
13906 val = (*auraItr)->GetAmount();
13907 }
13908 }
13909 }
13910 }
13911 return val;
13912}
13913
13914bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
13915{
13916 for (AuraEffect const* aurEff : aura->GetAuraEffects())
13917 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
13918 return false;
13919
13920 return true;
13921}
13922
13923bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
13924{
13925 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
13926 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
13927 {
13928 AuraEffect const* existingAurEff = (*itr);
13929 ++itr;
13930
13931 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
13932 {
13933 int64 diff = int64(abs(effectAmount)) - int64(abs(existingAurEff->GetAmount()));
13934 if (!diff)
13935 for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
13936 diff += int64((auraEffectMask & (1 << i)) >> i) - int64((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i);
13937
13938 if (diff > 0)
13939 {
13940 Aura const* base = existingAurEff->GetBase();
13941 // no removing of area auras from the original owner, as that completely cancels them
13942 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
13943 {
13944 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
13945 {
13946 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
13947 uint32 removedAuras = m_removedAurasCount;
13948 RemoveAura(aurApp);
13949 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
13950 itr = auras.begin();
13951 }
13952 }
13953 }
13954 else if (diff < 0)
13955 return false;
13956 }
13957 }
13958
13959 return true;
13960}
13961
13962void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
13963{
13964 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
13967 Cell::VisitWorldObjects(this, worker, textRange);
13968}
13969
13970void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13971{
13972 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13973}
13974
13975void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13976{
13977 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13978}
13979
13980void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13981{
13983}
13984
13985void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
13986{
13987 if (!target)
13988 return;
13989
13992 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
13993 target->SendDirectMessage(packet.Write());
13994}
13995
13997{
13998 if (slot >= MAX_EQUIPMENT_ITEMS)
13999 return 0;
14000
14001 return m_unitData->VirtualItems[slot].ItemID;
14002}
14003
14005{
14006 if (slot >= MAX_EQUIPMENT_ITEMS)
14007 return 0;
14008
14009 return m_unitData->VirtualItems[slot].ItemAppearanceModID;
14010}
14011
14012void Unit::SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId /*= 0*/, uint16 itemVisual /*= 0*/)
14013{
14014 if (slot >= MAX_EQUIPMENT_ITEMS)
14015 return;
14016
14017 auto virtualItemField = m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::VirtualItems, slot);
14018 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemID), itemId);
14019 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), appearanceModId);
14020 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemVisual), itemVisual);
14021}
14022
14023void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
14024{
14025 if (!sBroadcastTextStore.LookupEntry(textId))
14026 {
14027 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
14028 return;
14029 }
14030
14031 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
14034 Cell::VisitWorldObjects(this, worker, textRange);
14035}
14036
14037void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
14038{
14039 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
14040}
14041
14042void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
14043{
14044 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
14045}
14046
14047void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
14048{
14049 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
14050}
14051
14052void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
14053{
14054 if (!target)
14055 return;
14056
14057 BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(textId);
14058 if (!bct)
14059 {
14060 TC_LOG_ERROR("entities.unit", "WorldObject::Whisper: `broadcast_text` was not {} found", textId);
14061 return;
14062 }
14063
14066 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, GetGender()), 0, "", locale);
14067 target->SendDirectMessage(packet.Write());
14068}
14069
14070void Unit::ClearBossEmotes(Optional<uint32> zoneId, Player const* target) const
14071{
14073 clearBossEmotes.Write();
14074
14075 if (target)
14076 {
14077 target->SendDirectMessage(clearBossEmotes.GetRawPacket());
14078 return;
14079 }
14080
14081 for (MapReference const& ref : GetMap()->GetPlayers())
14082 if (!zoneId || DB2Manager::IsInArea(ref.GetSource()->GetAreaId(), *zoneId))
14083 ref.GetSource()->SendDirectMessage(clearBossEmotes.GetRawPacket());
14084}
14085
14087{
14088 for (uint32& slot : VisitedSpells)
14089 {
14090 if (slot == spellId)
14091 return false; // already exists
14092
14093 if (!slot)
14094 {
14095 slot = spellId;
14096 return true;
14097 }
14098 }
14099
14100 return false; // no free slots left
14101}
14102
14103SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag, GetCastSpellInfoContext* context) const
14104{
14105 auto findMatchingAuraEffectIn = [this, spellInfo, &triggerFlag, context](AuraType type) -> SpellInfo const*
14106 {
14107 for (AuraEffect const* auraEffect : GetAuraEffectsByType(type))
14108 {
14109 bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo);
14110 if (matches && context->AddSpell(auraEffect->GetAmount()))
14111 {
14112 if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount(), GetMap()->GetDifficultyID()))
14113 {
14114 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
14115 triggerFlag |= TRIGGERED_IGNORE_POWER_COST;
14116 else
14117 triggerFlag &= ~TRIGGERED_IGNORE_POWER_COST;
14118
14119 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR11_IGNORE_SPELLCAST_OVERRIDE_SHAPESHIFT_REQUIREMENTS))
14120 triggerFlag |= TRIGGERED_IGNORE_SHAPESHIFT;
14121 else
14122 triggerFlag &= ~TRIGGERED_IGNORE_SHAPESHIFT;
14123
14124 return newInfo;
14125 }
14126 }
14127 }
14128
14129 return nullptr;
14130 };
14131
14132 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS))
14133 {
14134 triggerFlag &= ~TRIGGERED_IGNORE_CAST_TIME;
14135 return GetCastSpellInfo(newInfo, triggerFlag, context);
14136 }
14137
14138 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED))
14139 {
14140 triggerFlag |= TRIGGERED_IGNORE_CAST_TIME;
14141 return GetCastSpellInfo(newInfo, triggerFlag, context);
14142 }
14143
14144 return spellInfo;
14145}
14146
14148{
14150 for (AuraEffect const* effect : visualOverrides)
14151 {
14152 if (uint32(effect->GetMiscValue()) == spellInfo->Id)
14153 {
14154 if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB(), GetMap()->GetDifficultyID()))
14155 {
14156 spellInfo = visualSpell;
14157 break;
14158 }
14159 }
14160 }
14161
14163}
14164
14166{
14167 return left->GetSlot() < right->GetSlot();
14168}
14169
14170// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
14172{
14173 float scaleMod = GetObjectScale(); // 99% sure about this
14174
14175 if (IsMounted())
14176 {
14177 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
14178 {
14179 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
14180 {
14181 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14182 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14183 float const collisionHeight = scaleMod * ((mountModelData->MountHeight * mountDisplayInfo->CreatureModelScale) + (modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f));
14184 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14185 }
14186 }
14187 }
14188
14190 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14191 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14192
14193 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
14194 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14195}
14196
14198{
14199 if (m_vignette)
14200 {
14201 if (m_vignette->Data->ID == vignetteId)
14202 return;
14203
14205 m_vignette = nullptr;
14206 }
14207
14208 if (VignetteEntry const* vignette = sVignetteStore.LookupEntry(vignetteId))
14209 m_vignette = Vignettes::Create(vignette, this);
14210}
14211
14212std::string Unit::GetDebugInfo() const
14213{
14214 std::stringstream sstr;
14215 sstr << WorldObject::GetDebugInfo() << "\n"
14216 << std::boolalpha
14217 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
14218 << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
14219 << " Class: " << std::to_string(GetClass()) << "\n"
14220 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
14221 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
14222 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
14223 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
14224 << "m_Controlled size: " << m_Controlled.size();
14225
14226 size_t controlledCount = 0;
14227 for (Unit* controlled : m_Controlled)
14228 {
14229 ++controlledCount;
14230 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
14231 }
14232
14233 return sstr.str();
14234}
14235
14237{
14238 for (std::size_t i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
14239 name[i] = uf.Name[i];
14240}
#define sBattlefieldMgr
@ SCORE_DAMAGE_DONE
@ SCORE_HEALING_DONE
#define sCharacterCache
CharmType
Definition: CharmInfo.h:69
@ CHARM_TYPE_CHARM
Definition: CharmInfo.h:70
@ CHARM_TYPE_POSSESS
Definition: CharmInfo.h:71
@ CHARM_TYPE_CONVERT
Definition: CharmInfo.h:73
@ CHARM_TYPE_VEHICLE
Definition: CharmInfo.h:72
LocaleConstant
Definition: Common.h:48
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
@ SEC_PLAYER
Definition: Common.h:40
@ SEC_GAMEMASTER
Definition: Common.h:42
#define M_PI
Definition: Common.h:115
#define sConditionMgr
Definition: ConditionMgr.h:368
#define sCreatureAIRegistry
@ CREATURE_FLAG_EXTRA_NO_BLOCK
Definition: CreatureData.h:347
@ CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS
Definition: CreatureData.h:348
@ CREATURE_FLAG_EXTRA_NO_CRIT
Definition: CreatureData.h:360
@ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
Definition: CreatureData.h:346
@ CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
Definition: CreatureData.h:362
@ CREATURE_FLAG_EXTRA_NO_PARRY
Definition: CreatureData.h:345
@ CREATURE_STATIC_FLAG_UNKILLABLE
Definition: CreatureData.h:41
DB2Storage< ArtifactAppearanceEntry > sArtifactAppearanceStore("ArtifactAppearance.db2", &ArtifactAppearanceLoadInfo::Instance)
DB2Storage< CreatureModelDataEntry > sCreatureModelDataStore("CreatureModelData.db2", &CreatureModelDataLoadInfo::Instance)
DB2Storage< LiquidTypeEntry > sLiquidTypeStore("LiquidType.db2", &LiquidTypeLoadInfo::Instance)
DB2Storage< AnimKitEntry > sAnimKitStore("AnimKit.db2", &AnimKitLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< SpellShapeshiftFormEntry > sSpellShapeshiftFormStore("SpellShapeshiftForm.db2", &SpellShapeshiftFormLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoExtraEntry > sCreatureDisplayInfoExtraStore("CreatureDisplayInfoExtra.db2", &CreatureDisplayInfoExtraLoadInfo::Instance)
DB2Storage< EmotesEntry > sEmotesStore("Emotes.db2", &EmotesLoadInfo::Instance)
DB2Storage< BroadcastTextEntry > sBroadcastTextStore("BroadcastText.db2", &BroadcastTextLoadInfo::Instance)
DB2Storage< VignetteEntry > sVignetteStore("Vignette.db2", &VignetteLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< ChrCustomizationReqEntry > sChrCustomizationReqStore("ChrCustomizationReq.db2", &ChrCustomizationReqLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance)
DB2Storage< PowerDisplayEntry > sPowerDisplayStore("PowerDisplay.db2", &PowerDisplayLoadInfo::Instance)
DB2Storage< FlightCapabilityEntry > sFlightCapabilityStore("FlightCapability.db2", &FlightCapabilityLoadInfo::Instance)
DB2Storage< MountCapabilityEntry > sMountCapabilityStore("MountCapability.db2", &MountCapabilityLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< VehicleEntry > sVehicleStore("Vehicle.db2", &VehicleLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:554
AreaMountFlags
Definition: DBCEnums.h:169
@ AllowUnderwaterSwimmingMounts
@ AllowSurfaceSwimmingMounts
@ DIFFICULTY_NONE
Definition: DBCEnums.h:919
#define MAX_EFFECT_MASK
Definition: DBCEnums.h:2122
@ UnitsUseDefaultPowerOnInit
#define MAX_SPELL_EFFECTS
Definition: DBCEnums.h:2121
@ MOUNT_CAPABILITY_FLAG_FLYING
Definition: DBCEnums.h:1845
@ MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS
Definition: DBCEnums.h:1848
@ MOUNT_CAPABILITY_FLAG_UNDERWATER
Definition: DBCEnums.h:1847
@ MOUNT_CAPABILITY_FLAG_GROUND
Definition: DBCEnums.h:1844
@ MOUNT_CAPABILITY_FLAG_FLOAT
Definition: DBCEnums.h:1846
#define TC_GAME_API
Definition: Define.h:123
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:24
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition: Duration.h:40
#define ABORT_MSG
Definition: Errors.h:75
#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:126
@ GROUP_UPDATE_FLAG_POWER_TYPE
Definition: Group.h:124
@ GROUP_UPDATE_FLAG_MAX_HP
Definition: Group.h:127
@ GROUP_UPDATE_FLAG_MAX_POWER
Definition: Group.h:129
@ GROUP_UPDATE_FLAG_AURAS
Definition: Group.h:137
@ GROUP_UPDATE_FLAG_LEVEL
Definition: Group.h:130
@ GROUP_UPDATE_FLAG_CUR_POWER
Definition: Group.h:128
@ GROUP_UPDATE_FLAG_PET_CUR_HP
Definition: Group.h:155
@ GROUP_UPDATE_FLAG_PET_AURAS
Definition: Group.h:157
@ GROUP_UPDATE_FLAG_PET_MAX_HP
Definition: Group.h:156
@ ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID
Definition: ItemDefines.h:231
@ ITEM_SUBCLASS_WEAPON_AXE2
Definition: ItemTemplate.h:501
@ ITEM_SUBCLASS_WEAPON_STAFF
Definition: ItemTemplate.h:510
@ ITEM_SUBCLASS_WEAPON_MACE
Definition: ItemTemplate.h:504
@ ITEM_SUBCLASS_WEAPON_EXOTIC2
Definition: ItemTemplate.h:512
@ ITEM_SUBCLASS_WEAPON_WARGLAIVES
Definition: ItemTemplate.h:509
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
Definition: ItemTemplate.h:520
@ ITEM_SUBCLASS_WEAPON_MACE2
Definition: ItemTemplate.h:505
@ ITEM_SUBCLASS_WEAPON_DAGGER
Definition: ItemTemplate.h:515
@ ITEM_SUBCLASS_WEAPON_SWORD
Definition: ItemTemplate.h:507
@ ITEM_SUBCLASS_WEAPON_AXE
Definition: ItemTemplate.h:500
@ ITEM_SUBCLASS_WEAPON_FIST_WEAPON
Definition: ItemTemplate.h:513
@ ITEM_SUBCLASS_WEAPON_EXOTIC
Definition: ItemTemplate.h:511
@ ITEM_SUBCLASS_WEAPON_THROWN
Definition: ItemTemplate.h:516
@ ITEM_SUBCLASS_WEAPON_SWORD2
Definition: ItemTemplate.h:508
@ ITEM_SUBCLASS_WEAPON_POLEARM
Definition: ItemTemplate.h:506
@ INVTYPE_SHIELD
Definition: ItemTemplate.h:399
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition: Log.h:179
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
#define TC_LOG_FATAL(filterType__, message__,...)
Definition: Log.h:191
LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true)
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > GenerateDungeonEncounterPersonalLoot(uint32 dungeonEncounterId, uint32 lootId, LootStore const &store, LootType type, WorldObject const *lootOwner, uint32 minMoney, uint32 maxMoney, uint16 lootMode, MapDifficultyEntry const *mapDifficulty, std::vector< Player * > const &tappers)
Definition: LootMgr.cpp:1037
@ LOOT_CORPSE
Definition: Loot.h:102
ZLiquidStatus
Definition: MapDefines.h:125
@ LIQUID_MAP_UNDER_WATER
Definition: MapDefines.h:130
@ LIQUID_MAP_OCEAN_FLOOR
Definition: MapDefines.h:131
@ LIQUID_MAP_IN_WATER
Definition: MapDefines.h:129
bool IsInvalidMovementSlot(uint8 const slot)
@ MOTION_PRIORITY_HIGHEST
@ MOTION_PRIORITY_NORMAL
MovementSlot
MovementGeneratorType
@ IDLE_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ CONFUSED_MOTION_TYPE
@ POINT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ EFFECT_MOTION_TYPE
MovementForceType
Definition: MovementInfo.h:152
#define DEFAULT_PLAYER_HOVER_HEIGHT
Definition: ObjectDefines.h:42
#define DEFAULT_PLAYER_DISPLAY_SCALE
Definition: ObjectDefines.h:41
#define NOMINAL_MELEE_RANGE
Definition: ObjectDefines.h:44
#define MIN_MELEE_REACH
Definition: ObjectDefines.h:43
@ NOTIFY_VISIBILITY_CHANGED
Definition: ObjectDefines.h:77
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:45
@ TYPEID_UNIT
Definition: ObjectGuid.h:42
@ TYPEID_PLAYER
Definition: ObjectGuid.h:43
@ TYPEMASK_UNIT
Definition: ObjectGuid.h:62
#define sObjectMgr
Definition: ObjectMgr.h:1986
float const DEFAULT_COLLISION_HEIGHT
Definition: Object.h:182
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ PETSPELL_REMOVED
Definition: PetDefines.h:73
PetActionFeedback
Definition: PetDefines.h:84
#define PET_FOLLOW_DIST
Definition: PetDefines.h:98
@ HUNTER_PET
Definition: PetDefines.h:32
@ PET_STABLE_ACTIVE
Definition: PetDefines.h:63
PetSaveMode
Definition: PetDefines.h:41
@ PET_SAVE_NOT_IN_SLOT
Definition: PetDefines.h:48
EquipmentSlots
Definition: Player.h:652
@ EQUIPMENT_SLOT_END
Definition: Player.h:673
@ EQUIPMENT_SLOT_OFFHAND
Definition: Player.h:670
@ TELE_TO_SPELL
Definition: Player.h:847
@ TELE_TO_NOT_LEAVE_COMBAT
Definition: Player.h:845
@ TELE_TO_NOT_UNSUMMON_PET
Definition: Player.h:846
@ TELE_TO_NONE
Definition: Player.h:842
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition: Player.h:844
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition: Player.h:300
@ CHEAT_GOD
Definition: Player.h:991
@ PLAYERSPELL_REMOVED
Definition: Player.h:197
#define INVENTORY_SLOT_BAG_0
Definition: Player.h:648
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition: Player.h:3349
Races
Definition: RaceMask.h:26
float rand_norm()
Definition: Random.cpp:75
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
bool roll_chance_f(float chance)
Definition: Random.h:53
bool roll_chance_i(int chance)
Definition: Random.h:59
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition: ScriptMgr.h:1417
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ SPELL_ATTR11_IGNORE_SPELLCAST_OVERRIDE_SHAPESHIFT_REQUIREMENTS
@ EFFECT_1
Definition: SharedDefines.h:31
@ EFFECT_0
Definition: SharedDefines.h:30
@ SPELL_ATTR10_RESET_COOLDOWN_ON_ENCOUNTER_END
#define MAX_STATS
@ SPELL_ATTR9_ALLOW_CAST_WHILE_CHANNELING
@ SPELL_ATTR9_IGNORE_CASTER_HEALING_MODIFIERS
@ SPELL_ATTR9_CANNOT_KILL_TARGET
#define MAX_POWERS_PER_CLASS
@ SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK
@ SPELL_ATTR7_DISPEL_REMOVES_CHARGES
@ SPELL_ATTR7_NO_ATTACK_PARRY
@ SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD
@ SPELL_ATTR7_NO_ATTACK_MISS
@ SPELL_ATTR7_NO_ATTACK_DODGE
Classes
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_ROGUE
Language
@ LANG_UNIVERSAL
Gender
@ SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL
@ SPELL_ATTR5_REMOVE_ENTERING_ARENA
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
@ NPC_CLICK_CAST_TARGET_CLICKER
@ NPC_CLICK_CAST_ORIG_CASTER_OWNER
@ NPC_CLICK_CAST_CASTER_CLICKER
Emote
@ EMOTE_ONESHOT_NONE
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ SPELL_SCHOOL_MASK_NONE
@ SPELL_SCHOOL_MASK_HOLY
@ EVENT_FACE
@ EVENT_VEHICLE_EXIT
@ SPELL_ATTR2_ALLOW_WHILE_INVISIBLE
@ SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE
@ SPELL_ATTR2_ALLOW_DEAD_TARGET
@ SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS
@ SPELL_ATTR2_NO_SCHOOL_IMMUNITIES
@ ANIM_MOUNT_SPECIAL
@ ANIM_MOUNT_SELF_SPECIAL
SummonTitle
@ CREATURE_TYPE_DEMON
@ SPELL_ATTR1_ALLOW_WHILE_STEALTHED
@ SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT
@ SPELL_ATTR1_IMMUNITY_PURGES_EFFECT
@ SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS
@ UNIT_DYNFLAG_SPECIALINFO
@ UNIT_DYNFLAG_LOOTABLE
@ UNIT_DYNFLAG_CAN_SKIN
@ SPELL_ATTR3_TREAT_AS_PERIODIC
@ SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD
@ SPELL_ATTR3_SUPPRESS_TARGET_PROCS
@ SPELL_ATTR3_NO_DURABILITY_LOSS
@ SPELL_ATTR3_ALWAYS_HIT
@ SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON
@ SPELL_ATTR3_SUPPRESS_CASTER_PROCS
@ SPELL_ATTR3_NO_AVOIDANCE
@ SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON
@ SPELL_ATTR3_IGNORE_CASTER_MODIFIERS
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ AI_REACTION_HOSTILE
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_SUMMON
@ MAX_SUMMON_SLOT
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
#define PER_CASTER_AURA_STATE_MASK
Mechanics
@ MECHANIC_NONE
@ MECHANIC_ROOT
@ MECHANIC_BLEED
@ MECHANIC_DAZE
@ MECHANIC_SNARE
SpellImmunity
@ IMMUNITY_STATE
@ IMMUNITY_EFFECT
@ IMMUNITY_ID
@ IMMUNITY_DAMAGE
@ IMMUNITY_MECHANIC
@ IMMUNITY_SCHOOL
@ IMMUNITY_OTHER
@ IMMUNITY_DISPEL
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_ENERGY
@ POWER_MANA
@ POWER_FOCUS
@ SPELL_ATTR0_NO_ACTIVE_DEFENSE
@ SPELL_ATTR0_ALLOW_WHILE_MOUNTED
@ SPELL_ATTR0_NO_IMMUNITIES
@ SPELL_ATTR0_NO_AURA_CANCEL
@ SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE
@ SPELL_ATTR0_NOT_IN_COMBAT_ONLY_PEACEFUL
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_AOE_KNOCKBACK
@ DIMINISHING_NONE
@ DIMINISHING_TAUNT
SpellCastResult
@ SPELL_FAILED_SUCCESS
@ SPELL_CAST_OK
@ GHOST_VISIBILITY_ALIVE
@ SPELL_HIT_TYPE_CRIT
Stats
@ STAT_INTELLECT
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
AuraStateType
@ AURA_STATE_WOUNDED_20_PERCENT
@ AURA_STATE_HEALTHY_75_PERCENT
@ AURA_STATE_FROZEN
@ AURA_STATE_WOUNDED_35_PERCENT
@ AURA_STATE_ENRAGED
@ AURA_STATE_WOUND_HEALTH_35_80
@ AURA_STATE_DEFENSIVE_2
@ AURA_STATE_WOUND_HEALTH_20_80
@ AURA_STATE_WOUNDED_25_PERCENT
@ AURA_STATE_WOUNDED_50_PERCENT
@ AURA_STATE_DEFENSIVE
@ DRTYPE_PLAYER
@ DRTYPE_ALL
SpellFamilyNames
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_POTION
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_DRUID
@ SPELL_ATTR13_DO_NOT_ALLOW_DISABLE_MOVEMENT_INTERRUPT
@ SPELL_ATTR13_ALWAYS_ALLOW_NEGATIVE_HEALING_PERCENT_MODIFIERS
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
@ DISPEL_DISEASE
@ DISPEL_INVISIBILITY
@ DISPEL_STEALTH
#define MAX_GAMEOBJECT_SLOT
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
@ SPELL_ATTR4_NO_HARMFUL_THREAT
@ SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS
@ SPELL_ATTR4_NO_PARTIAL_IMMUNITY
@ SPELL_ATTR4_REACTIVE_DAMAGE_PROC
@ SPELL_ATTR4_ALLOW_ENTERING_ARENA
@ SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST
@ SPELL_ATTR8_NO_ATTACK_BLOCK
@ SKILL_RIDING
@ SPELL_ATTR6_NO_PUSHBACK
@ SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS
@ SPELL_ATTR6_IGNORE_HEALING_MODIFIERS
@ SPELL_ATTR6_ABSORB_CANNOT_BE_IGNORE
@ SPELL_ATTR6_DELAY_COMBAT_TIMER_DURING_CAST
AuraTriggerOnHealthChangeDirection
@ AURA_EFFECT_HANDLE_STAT
@ AURA_EFFECT_HANDLE_SEND_FOR_CLIENT
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_REMOVE_BY_INTERRUPT
AuraType
@ SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
@ SPELL_AURA_MANA_SHIELD
@ SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER_BY_LABEL
@ SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER
@ SPELL_AURA_MOD_ADV_FLYING_LIFT_COEF
@ SPELL_AURA_CLONE_CASTER
@ 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_PERIODIC_DAMAGE_TAKEN
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@ SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS
@ SPELL_AURA_MOD_AUTOATTACK_RANGE
@ SPELL_AURA_MOD_ADV_FLYING_ADD_IMPULSE_MAX_SPEED
@ 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_DISABLE_ATTACKING_EXCEPT_ABILITIES
@ SPELL_AURA_MOD_ADV_FLYING_MAX_VEL
@ SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER
@ SPELL_AURA_PERIODIC_HEALTH_FUNNEL
@ SPELL_AURA_IGNORE_DUAL_WIELD_HIT_PENALTY
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_MOD_INCREASE_SPEED
@ SPELL_AURA_MOD_EXPERTISE
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
@ SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL
@ SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
@ SPELL_AURA_MOD_HEALING_DONE_PERCENT
@ SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_DOWN
@ SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH
@ SPELL_AURA_CAST_WHILE_WALKING_BY_SPELL_LABEL
@ SPELL_AURA_LINKED
@ SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_PCT
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
@ SPELL_AURA_SHARE_DAMAGE_PCT
@ SPELL_AURA_CAST_WHILE_WALKING
@ SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@ SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER
@ SPELL_AURA_TRIGGER_SPELL_ON_POWER_AMOUNT
@ 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_HEALING_DONE_PCT_VERSUS_TARGET_HEALTH
@ SPELL_AURA_MOD_STALKED
@ SPELL_AURA_SCHOOL_HEAL_ABSORB
@ SPELL_AURA_MOD_ROOT_2
@ SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
@ SPELL_AURA_COSMETIC_MOUNTED
@ SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
@ 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_MOD_DAMAGE_PERCENT_TAKEN
@ SPELL_AURA_MOD_STUN_DISABLE_GRAVITY
@ SPELL_AURA_MOD_DODGE_PERCENT
@ SPELL_AURA_MOD_INCREASE_SWIM_SPEED
@ SPELL_AURA_SPLIT_DAMAGE_PCT
@ SPELL_AURA_SCHOOL_ABSORB_OVERKILL
@ 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_CRIT_CHANCE_FOR_CASTER_PET
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
@ SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
@ SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED
@ SPELL_AURA_MOD_ARMOR_PENETRATION_PCT
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_MOD_CRITICAL_DAMAGE_TAKEN_FROM_CASTER
@ SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOUNT_RESTRICTIONS
@ SPELL_AURA_OVERRIDE_SPELL_VISUAL
@ SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
@ SPELL_AURA_MOD_CRITICAL_BLOCK_AMOUNT
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_DAMAGE_TAKEN
@ SPELL_AURA_MOD_FACTION
@ SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE
@ SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS
@ SPELL_AURA_MOD_POWER_GAIN_PCT
@ SPELL_AURA_MOD_CRIT_PCT
@ SPELL_AURA_MOD_MINIMUM_SPEED
@ SPELL_AURA_MOD_BLOCK_CRIT_CHANCE
@ SPELL_AURA_MOD_HOT_PCT
@ SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE_BY_TARGET_AURA_MECHANIC
@ SPELL_AURA_MOD_SCALE_2
@ SPELL_AURA_MOD_POWER_DISPLAY
@ SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_MOD_TARGET_RESISTANCE
@ SPELL_AURA_MOD_MINIMUM_SPEED_RATE
@ SPELL_AURA_MOD_SPEED_ALWAYS
@ SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY
@ SPELL_AURA_MOD_DECREASE_SPEED
@ SPELL_AURA_MOD_VERSATILITY
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_CAST_WHILE_WALKING_ALL
@ SPELL_AURA_SCHOOL_ABSORB
@ SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC
@ SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
@ SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_MOD_MOVEMENT_FORCE_MAGNITUDE
@ SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
@ SPELL_AURA_MOD_SCALE
@ SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL
@ SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT
@ SPELL_AURA_MOD_ADV_FLYING_AIR_FRICTION
@ SPELL_AURA_MOD_DURABILITY_LOSS
@ SPELL_AURA_MOD_ADV_FLYING_OVER_MAX_DECELERATION
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_MOD_AUTOATTACK_CRIT_CHANCE
@ SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT
@ SPELL_AURA_ACT_AS_CONTROL_ZONE
@ SPELL_AURA_MOD_PERCENT_STAT
@ SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE
@ SPELL_AURA_MOD_AUTOATTACK_DAMAGE
@ SPELL_AURA_MOD_HEALING
@ SPELL_AURA_MOD_DAMAGE_DONE
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_MECHANIC_RESISTANCE
@ SPELL_AURA_MOD_UNATTACKABLE
@ SPELL_AURA_MOD_DAMAGE_TAKEN_BY_LABEL
@ 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_OVERRIDE_ACTIONBAR_SPELLS
@ SPELL_AURA_INTERCEPT_MELEE_RANGED_ATTACKS
@ SPELL_AURA_MOD_BLOCK_PERCENT
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
ShapeshiftForm
@ FORM_BEAR_FORM
@ FORM_DIRE_BEAR_FORM
@ FORM_GHOST_WOLF
@ FORM_FLIGHT_FORM_EPIC
@ FORM_CAT_FORM
@ FORM_AQUATIC_FORM
@ FORM_NONE
@ FORM_TRAVEL_FORM
@ FORM_FLIGHT_FORM
@ FORM_GHOUL
@ UNIT_AURA_TYPE
AuraTriggerOnPowerChangeDirection
SpellValueMod
Definition: SpellDefines.h:198
@ SPELLVALUE_BASE_POINT0
Definition: SpellDefines.h:199
SpellAuraInterruptFlags2
Definition: SpellDefines.h:119
@ PeriodicHealingAndDamage
@ CritDamageAndHealing
TriggerCastFlags
Definition: SpellDefines.h:256
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
Definition: SpellDefines.h:271
@ TRIGGERED_IGNORE_SHAPESHIFT
Will ignore shapeshift checks.
Definition: SpellDefines.h:268
@ TRIGGERED_IGNORE_POWER_COST
Will ignore power and reagent cost.
Definition: SpellDefines.h:260
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
Definition: SpellDefines.h:258
@ TRIGGERED_NONE
Not triggered.
Definition: SpellDefines.h:257
@ TRIGGERED_IGNORE_CAST_TIME
Will always be instantly cast.
Definition: SpellDefines.h:264
SpellAuraInterruptFlags
Definition: SpellDefines.h:78
std::vector< AuraEffect * > AuraEffectVector
Definition: SpellInfo.h:299
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition: SpellInfo.h:159
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition: SpellInfo.h:144
@ SPELL_ATTR0_CU_CAN_CRIT
Definition: SpellInfo.h:151
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition: SpellInfo.h:161
@ SPELL_ATTR0_CU_AURA_CC
Definition: SpellInfo.h:149
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition: SpellInfo.h:164
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition: SpellInfo.h:165
@ SPELL_SPECIFIC_MAGE_POLYMORPH
Definition: SpellInfo.h:127
#define MELEE_BASED_TRIGGER_MASK
Definition: SpellMgr.h:245
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition: SpellMgr.h:380
ProcFlagsSpellPhase
Definition: SpellMgr.h:266
@ PROC_SPELL_PHASE_NONE
Definition: SpellMgr.h:267
@ PROC_SPELL_PHASE_HIT
Definition: SpellMgr.h:269
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition: SpellMgr.h:391
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition: SpellMgr.h:392
#define sSpellMgr
Definition: SpellMgr.h:855
ProcFlagsSpellType
Definition: SpellMgr.h:255
@ PROC_SPELL_TYPE_NONE
Definition: SpellMgr.h:256
@ PROC_SPELL_TYPE_MASK_ALL
Definition: SpellMgr.h:260
@ PROC_SPELL_TYPE_DAMAGE
Definition: SpellMgr.h:257
@ PROC_FLAG_MAIN_HAND_WEAPON_SWING
Definition: SpellMgr.h:172
@ PROC_FLAG_TAKE_MELEE_SWING
Definition: SpellMgr.h:142
@ PROC_FLAG_TAKE_ANY_DAMAGE
Definition: SpellMgr.h:168
@ PROC_FLAG_ENCOUNTER_START
Definition: SpellMgr.h:183
@ PROC_FLAG_DEAL_MELEE_SWING
Definition: SpellMgr.h:141
@ PROC_FLAG_HEARTBEAT
Definition: SpellMgr.h:138
@ PROC_FLAG_TAKE_HARMFUL_SPELL
Definition: SpellMgr.h:163
@ PROC_FLAG_DEATH
Definition: SpellMgr.h:175
@ PROC_FLAG_OFF_HAND_WEAPON_SWING
Definition: SpellMgr.h:173
@ PROC_FLAG_ENTER_COMBAT
Definition: SpellMgr.h:181
@ PROC_FLAG_KILL
Definition: SpellMgr.h:139
@ PROC_FLAG_NONE
Definition: SpellMgr.h:136
@ PROC_FLAG_2_TARGET_DIES
Definition: SpellMgr.h:234
ProcFlagsHit
Definition: SpellMgr.h:277
@ PROC_HIT_BLOCK
Definition: SpellMgr.h:285
@ PROC_HIT_FULL_RESIST
Definition: SpellMgr.h:282
@ PROC_HIT_FULL_BLOCK
Definition: SpellMgr.h:292
@ PROC_HIT_MISS
Definition: SpellMgr.h:281
@ PROC_HIT_NONE
Definition: SpellMgr.h:278
@ PROC_HIT_DEFLECT
Definition: SpellMgr.h:288
@ PROC_HIT_EVADE
Definition: SpellMgr.h:286
@ PROC_HIT_DODGE
Definition: SpellMgr.h:283
@ PROC_HIT_IMMUNE
Definition: SpellMgr.h:287
@ PROC_HIT_ABSORB
Definition: SpellMgr.h:289
@ PROC_HIT_PARRY
Definition: SpellMgr.h:284
@ PROC_HIT_CRITICAL
Definition: SpellMgr.h:280
@ PROC_HIT_NORMAL
Definition: SpellMgr.h:279
@ PROC_HIT_REFLECT
Definition: SpellMgr.h:290
SpellOtherImmunity
Definition: SpellMgr.h:598
@ SPELL_CAST_SOURCE_NORMAL
Definition: Spell.h:153
@ SPELL_STATE_DELAYED
Definition: Spell.h:246
@ SPELL_STATE_FINISHED
Definition: Spell.h:244
@ SPELL_STATE_PREPARING
Definition: Spell.h:242
@ SPELL_STATE_CASTING
Definition: Spell.h:243
@ SPELL_STATE_IDLE
Definition: Spell.h:245
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
@ TOTEM_PASSIVE
Definition: Totem.h:25
UnitMoveType
Definition: UnitDefines.h:116
@ MOVE_FLIGHT
Definition: UnitDefines.h:123
@ MOVE_SWIM
Definition: UnitDefines.h:120
@ MOVE_FLIGHT_BACK
Definition: UnitDefines.h:124
@ MOVE_SWIM_BACK
Definition: UnitDefines.h:121
@ MOVE_RUN
Definition: UnitDefines.h:118
@ MOVE_RUN_BACK
Definition: UnitDefines.h:119
@ MOVE_WALK
Definition: UnitDefines.h:117
@ UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS
Definition: UnitDefines.h:241
@ UNIT_FLAG2_INTERACT_WHILE_HOSTILE
Definition: UnitDefines.h:231
@ UNIT_FLAG2_CANNOT_TURN
Definition: UnitDefines.h:232
@ UNIT_FLAG2_DISARM_OFFHAND
Definition: UnitDefines.h:224
@ UNIT_FLAG2_DISARM_RANGED
Definition: UnitDefines.h:227
HitInfo
Definition: UnitDefines.h:481
@ HITINFO_PARTIAL_ABSORB
Definition: UnitDefines.h:489
@ HITINFO_FULL_RESIST
Definition: UnitDefines.h:490
@ HITINFO_NORMALSWING
Definition: UnitDefines.h:482
@ HITINFO_BLOCK
Definition: UnitDefines.h:496
@ HITINFO_CRUSHING
Definition: UnitDefines.h:500
@ HITINFO_FAKE_DAMAGE
Definition: UnitDefines.h:507
@ HITINFO_SWINGNOHITSOUND
Definition: UnitDefines.h:504
@ HITINFO_MISS
Definition: UnitDefines.h:487
@ HITINFO_RAGE_GAIN
Definition: UnitDefines.h:506
@ HITINFO_FULL_ABSORB
Definition: UnitDefines.h:488
@ HITINFO_NO_ANIMATION
Definition: UnitDefines.h:501
@ HITINFO_OFFHAND
Definition: UnitDefines.h:485
@ HITINFO_GLANCING
Definition: UnitDefines.h:499
@ HITINFO_CRITICALHIT
Definition: UnitDefines.h:492
@ HITINFO_PARTIAL_RESIST
Definition: UnitDefines.h:491
@ HITINFO_AFFECTS_VICTIM
Definition: UnitDefines.h:484
@ REACT_PASSIVE
Definition: UnitDefines.h:540
UnitStandStateType
Definition: UnitDefines.h:41
@ UNIT_STAND_STATE_SLEEP
Definition: UnitDefines.h:45
@ UNIT_STAND_STATE_SIT_HIGH_CHAIR
Definition: UnitDefines.h:48
@ UNIT_STAND_STATE_SIT_MEDIUM_CHAIR
Definition: UnitDefines.h:47
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition: UnitDefines.h:46
@ UNIT_STAND_STATE_KNEEL
Definition: UnitDefines.h:50
@ UNIT_STAND_STATE_SIT_CHAIR
Definition: UnitDefines.h:44
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
@ UNIT_STAND_STATE_SIT
Definition: UnitDefines.h:43
AdvFlyingRateTypeSingle
Definition: UnitDefines.h:131
@ ADV_FLYING_DOUBLE_JUMP_VEL_MOD
Definition: UnitDefines.h:135
@ ADV_FLYING_OVER_MAX_DECELERATION
Definition: UnitDefines.h:139
@ ADV_FLYING_LIFT_COEFFICIENT
Definition: UnitDefines.h:134
@ ADV_FLYING_ADD_IMPULSE_MAX_SPEED
Definition: UnitDefines.h:137
@ ADV_FLYING_GLIDE_START_MIN_HEIGHT
Definition: UnitDefines.h:136
@ ADV_FLYING_AIR_FRICTION
Definition: UnitDefines.h:132
@ ADV_FLYING_LAUNCH_SPEED_COEFFICIENT
Definition: UnitDefines.h:140
@ ADV_FLYING_MAX_VEL
Definition: UnitDefines.h:133
@ ADV_FLYING_SURFACE_FRICTION
Definition: UnitDefines.h:138
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:386
@ MOVEMENTFLAG_WATERWALKING
Definition: UnitDefines.h:412
@ MOVEMENTFLAG_MASK_MOVING
Definition: UnitDefines.h:417
@ MOVEMENTFLAG_DISABLE_GRAVITY
Definition: UnitDefines.h:395
@ MOVEMENTFLAG_FALLING_SLOW
Definition: UnitDefines.h:413
@ MOVEMENTFLAG_CAN_FLY
Definition: UnitDefines.h:409
@ MOVEMENTFLAG_ROOT
Definition: UnitDefines.h:396
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:397
@ MOVEMENTFLAG_MASK_MOVING_FLY
Definition: UnitDefines.h:424
@ MOVEMENTFLAG_FALLING_FAR
Definition: UnitDefines.h:398
@ MOVEMENTFLAG_SWIMMING
Definition: UnitDefines.h:406
@ MOVEMENTFLAG_HOVER
Definition: UnitDefines.h:414
@ MOVEMENTFLAG_SPLINE_ELEVATION
Definition: UnitDefines.h:411
@ MOVEMENTFLAG_WALKING
Definition: UnitDefines.h:394
@ MOVEMENTFLAG_DISABLE_COLLISION
Definition: UnitDefines.h:415
#define MAX_MOVE_TYPE
Definition: UnitDefines.h:128
@ MOVEMENTFLAG2_CAN_DOUBLE_JUMP
Definition: UnitDefines.h:458
@ MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS
Definition: UnitDefines.h:454
@ MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING
Definition: UnitDefines.h:456
@ MOVEMENTFLAG2_IGNORE_MOVEMENT_FORCES
Definition: UnitDefines.h:457
@ MOVEMENTFLAG2_FULL_SPEED_TURNING
Definition: UnitDefines.h:448
#define MAX_DECLINED_NAME_CASES
Definition: UnitDefines.h:518
AdvFlyingRateTypeRange
Definition: UnitDefines.h:144
@ ADV_FLYING_PITCHING_RATE_DOWN
Definition: UnitDefines.h:146
@ ADV_FLYING_TURN_VELOCITY_THRESHOLD
Definition: UnitDefines.h:148
@ ADV_FLYING_PITCHING_RATE_UP
Definition: UnitDefines.h:147
@ ADV_FLYING_BANKING_RATE
Definition: UnitDefines.h:145
@ UNIT_NPC_FLAG_TABARDDESIGNER
Definition: UnitDefines.h:339
@ UNIT_NPC_FLAG_SPIRIT_HEALER
Definition: UnitDefines.h:334
@ UNIT_NPC_FLAG_BANKER
Definition: UnitDefines.h:337
@ UNIT_NPC_FLAG_AUCTIONEER
Definition: UnitDefines.h:341
@ UNIT_NPC_FLAG_AREA_SPIRIT_HEALER
Definition: UnitDefines.h:335
@ UNIT_NPC_FLAG_VENDOR
Definition: UnitDefines.h:327
@ UNIT_NPC_FLAG_BATTLEMASTER
Definition: UnitDefines.h:340
@ UNIT_NPC_FLAG_INNKEEPER
Definition: UnitDefines.h:336
@ UNIT_NPC_FLAG_SPELLCLICK
Definition: UnitDefines.h:344
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
Definition: UnitDefines.h:345
@ UNIT_NPC_FLAG_FLIGHTMASTER
Definition: UnitDefines.h:333
@ UNIT_NPC_FLAG_TRAINER
Definition: UnitDefines.h:324
@ UNIT_NPC_FLAG_PETITIONER
Definition: UnitDefines.h:338
DamageEffectType
Definition: UnitDefines.h:154
@ SELF_DAMAGE
Definition: UnitDefines.h:160
@ DIRECT_DAMAGE
Definition: UnitDefines.h:155
@ NODAMAGE
Definition: UnitDefines.h:159
@ DOT
Definition: UnitDefines.h:157
@ SPELL_DIRECT_DAMAGE
Definition: UnitDefines.h:156
#define BASE_MAXDAMAGE
Definition: UnitDefines.h:34
@ UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT
Definition: UnitDefines.h:289
SheathState
Definition: UnitDefines.h:81
@ SHEATH_STATE_UNARMED
Definition: UnitDefines.h:82
@ MOVEMENTFLAG3_ADV_FLYING
Definition: UnitDefines.h:473
@ MOVEMENTFLAG3_CANT_SWIM
Definition: UnitDefines.h:474
@ MOVEMENTFLAG3_DISABLE_INERTIA
Definition: UnitDefines.h:471
@ MOVEMENTFLAG3_CAN_ADV_FLY
Definition: UnitDefines.h:472
#define MAX_EQUIPMENT_ITEMS
Definition: UnitDefines.h:37
@ UNIT_BYTE2_FLAG_PVP
Definition: UnitDefines.h:93
@ UNIT_BYTE2_FLAG_NONE
Definition: UnitDefines.h:92
AnimTier
Definition: UnitDefines.h:69
@ COMMAND_FOLLOW
Definition: UnitDefines.h:561
#define BASE_MINDAMAGE
Definition: UnitDefines.h:33
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:185
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:168
@ UNIT_FLAG_IMMUNE_TO_NPC
Definition: UnitDefines.h:176
@ UNIT_FLAG_POSSESSED
Definition: UnitDefines.h:191
@ UNIT_FLAG_DISARMED
Definition: UnitDefines.h:188
@ UNIT_FLAG_PACIFIED
Definition: UnitDefines.h:184
@ UNIT_FLAG_CAN_SWIM
Definition: UnitDefines.h:182
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
Definition: UnitDefines.h:169
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:190
@ UNIT_FLAG_CANT_SWIM
Definition: UnitDefines.h:181
@ UNIT_FLAG_RENAME
Definition: UnitDefines.h:171
@ UNIT_FLAG_UNINTERACTIBLE
Definition: UnitDefines.h:192
@ UNIT_FLAG_IMMUNE_TO_PC
Definition: UnitDefines.h:175
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:170
@ UNIT_FLAG_SKINNABLE
Definition: UnitDefines.h:193
@ UNIT_FLAG_MOUNT
Definition: UnitDefines.h:194
@ UNIT_FLAG_PET_IN_COMBAT
Definition: UnitDefines.h:178
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:97
bool IsInterruptFlagIgnoredForSpell(InterruptFlag, Unit const *, SpellInfo const *, bool, SpellInfo const *)
Definition: Unit.cpp:4136
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition: Unit.cpp:10160
static uint32 CalcMeleeAttackRageGain(Unit const *attacker, WeaponAttackType attType)
Definition: Unit.cpp:2204
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition: Unit.cpp:10714
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:110
UnitModifierFlatType
Definition: Unit.h:154
@ BASE_VALUE
Definition: Unit.h:155
@ MODIFIER_TYPE_FLAT_END
Definition: Unit.h:158
@ TOTAL_VALUE
Definition: Unit.h:157
@ BASE_PCT_EXCLUDE_CREATE
Definition: Unit.h:156
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition: Unit.h:151
@ UNIT_MASK_NONE
Definition: Unit.h:352
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition: Unit.h:361
@ UNIT_MASK_ACCESSORY
Definition: Unit.h:362
@ UNIT_MASK_VEHICLE
Definition: Unit.h:358
@ UNIT_MASK_GUARDIAN
Definition: Unit.h:355
@ UNIT_MASK_MINION
Definition: Unit.h:354
VictimState
Definition: Unit.h:48
@ VICTIMSTATE_INTACT
Definition: Unit.h:49
@ VICTIMSTATE_HIT
Definition: Unit.h:50
@ VICTIMSTATE_DODGE
Definition: Unit.h:51
@ VICTIMSTATE_IS_IMMUNE
Definition: Unit.h:56
@ VICTIMSTATE_PARRY
Definition: Unit.h:52
@ VICTIMSTATE_BLOCKS
Definition: Unit.h:54
@ VICTIMSTATE_EVADES
Definition: Unit.h:55
WeaponDamageRange
Definition: Unit.h:169
@ MINDAMAGE
Definition: Unit.h:170
@ MAXDAMAGE
Definition: Unit.h:171
UnitMods
Definition: Unit.h:175
@ UNIT_MOD_DAMAGE_OFFHAND
Definition: Unit.h:217
@ UNIT_MOD_COMBO_POINTS
Definition: Unit.h:185
@ UNIT_MOD_STAT_INTELLECT
Definition: Unit.h:179
@ UNIT_MOD_ARMOR
Definition: Unit.h:207
@ UNIT_MOD_RESISTANCE_SHADOW
Definition: Unit.h:212
@ UNIT_MOD_RESISTANCE_FROST
Definition: Unit.h:211
@ UNIT_MOD_END
Definition: Unit.h:219
@ UNIT_MOD_ATTACK_POWER
Definition: Unit.h:214
@ UNIT_MOD_RESISTANCE_HOLY
Definition: Unit.h:208
@ UNIT_MOD_RESISTANCE_START
Definition: Unit.h:223
@ UNIT_MOD_SOUL_SHARDS
Definition: Unit.h:188
@ UNIT_MOD_RESISTANCE_ARCANE
Definition: Unit.h:213
@ UNIT_MOD_ESSENCE
Definition: Unit.h:200
@ UNIT_MOD_ARCANE_CHARGES
Definition: Unit.h:197
@ UNIT_MOD_ENERGY
Definition: Unit.h:184
@ UNIT_MOD_HEALTH
Definition: Unit.h:180
@ UNIT_MOD_RUNES
Definition: Unit.h:186
@ UNIT_MOD_DAMAGE_RANGED
Definition: Unit.h:218
@ UNIT_MOD_HOLY_POWER
Definition: Unit.h:190
@ UNIT_MOD_PAIN
Definition: Unit.h:199
@ UNIT_MOD_BURNING_EMBERS
Definition: Unit.h:195
@ UNIT_MOD_RUNE_UNHOLY
Definition: Unit.h:203
@ UNIT_MOD_POWER_START
Definition: Unit.h:225
@ UNIT_MOD_RUNE_BLOOD
Definition: Unit.h:201
@ UNIT_MOD_CHI
Definition: Unit.h:193
@ UNIT_MOD_RESISTANCE_FIRE
Definition: Unit.h:209
@ UNIT_MOD_STAT_STRENGTH
Definition: Unit.h:176
@ UNIT_MOD_RUNE_FROST
Definition: Unit.h:202
@ UNIT_MOD_FURY
Definition: Unit.h:198
@ UNIT_MOD_ALTERNATE
Definition: Unit.h:191
@ UNIT_MOD_RESISTANCE_NATURE
Definition: Unit.h:210
@ UNIT_MOD_ALTERNATE_ENCOUNTER
Definition: Unit.h:205
@ UNIT_MOD_LUNAR_POWER
Definition: Unit.h:189
@ UNIT_MOD_MAELSTROM
Definition: Unit.h:192
@ UNIT_MOD_DEMONIC_FURY
Definition: Unit.h:196
@ UNIT_MOD_ALTERNATE_QUEST
Definition: Unit.h:204
@ UNIT_MOD_STAT_AGILITY
Definition: Unit.h:177
@ UNIT_MOD_ALTERNATE_MOUNT
Definition: Unit.h:206
@ UNIT_MOD_INSANITY
Definition: Unit.h:194
@ UNIT_MOD_FOCUS
Definition: Unit.h:183
@ UNIT_MOD_DAMAGE_MAINHAND
Definition: Unit.h:216
@ UNIT_MOD_MANA
Definition: Unit.h:181
@ UNIT_MOD_STAT_START
Definition: Unit.h:221
@ UNIT_MOD_RAGE
Definition: Unit.h:182
@ UNIT_MOD_STAT_STAMINA
Definition: Unit.h:178
@ UNIT_MOD_RUNIC_POWER
Definition: Unit.h:187
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition: Unit.h:215
DeathState
Definition: Unit.h:248
@ CORPSE
Definition: Unit.h:251
@ DEAD
Definition: Unit.h:252
@ ALIVE
Definition: Unit.h:249
@ JUST_RESPAWNED
Definition: Unit.h:253
@ JUST_DIED
Definition: Unit.h:250
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition: Unit.h:599
CurrentSpellTypes
Definition: Unit.h:592
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:595
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:594
@ CURRENT_MELEE_SPELL
Definition: Unit.h:593
@ CURRENT_AUTOREPEAT_SPELL
Definition: Unit.h:596
UnitState
Definition: Unit.h:257
@ UNIT_STATE_DISTRACTED
Definition: Unit.h:270
@ UNIT_STATE_DIED
Definition: Unit.h:258
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:272
@ UNIT_STATE_POSSESSED
Definition: Unit.h:274
@ UNIT_STATE_UNATTACKABLE
Definition: Unit.h:296
@ UNIT_STATE_LOST_CONTROL
Definition: Unit.h:299
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition: Unit.h:300
@ UNIT_STATE_CONFUSED
Definition: Unit.h:269
@ UNIT_STATE_ROOT
Definition: Unit.h:268
@ UNIT_STATE_CHARGING
Definition: Unit.h:275
@ UNIT_STATE_CONTROLLED
Definition: Unit.h:298
@ UNIT_STATE_FLEEING
Definition: Unit.h:265
@ UNIT_STATE_CANNOT_TURN
Definition: Unit.h:302
@ UNIT_STATE_MOVING
Definition: Unit.h:297
@ UNIT_STATE_MOVE
Definition: Unit.h:278
@ UNIT_STATE_MELEE_ATTACKING
Definition: Unit.h:259
@ UNIT_STATE_IN_FLIGHT
Definition: Unit.h:266
@ UNIT_STATE_FOCUSING
Definition: Unit.h:264
@ UNIT_STATE_CASTING
Definition: Unit.h:273
@ UNIT_STATE_STUNNED
Definition: Unit.h:261
@ UNIT_STATE_CHARMED
Definition: Unit.h:260
MeleeHitOutcome
Definition: Unit.h:382
@ MELEE_HIT_CRUSHING
Definition: Unit.h:384
@ MELEE_HIT_BLOCK
Definition: Unit.h:383
@ MELEE_HIT_CRIT
Definition: Unit.h:384
@ MELEE_HIT_NORMAL
Definition: Unit.h:384
@ MELEE_HIT_EVADE
Definition: Unit.h:383
@ MELEE_HIT_DODGE
Definition: Unit.h:383
@ MELEE_HIT_MISS
Definition: Unit.h:383
@ MELEE_HIT_PARRY
Definition: Unit.h:383
@ MELEE_HIT_GLANCING
Definition: Unit.h:384
#define MAX_AGGRO_RESET_TIME
Definition: Unit.h:44
#define SPELL_DAZED
Definition: Unit.h:37
#define ATTACK_DISPLAY_DELAY
Definition: Unit.h:627
std::vector< DispelableAura > DispelChargesList
Definition: Unit.h:149
#define CURRENT_MAX_SPELL
Definition: Unit.h:600
CombatRating
Definition: Unit.h:313
@ CR_VERSATILITY_DAMAGE_TAKEN
Definition: Unit.h:344
@ CR_ARMOR_PENETRATION
Definition: Unit.h:338
@ CR_VERSATILITY_DAMAGE_DONE
Definition: Unit.h:342
ReactiveType
Definition: Unit.h:608
@ MAX_REACTIVE
Definition: Unit.h:611
@ REACTIVE_DEFENSE
Definition: Unit.h:609
@ REACTIVE_DEFENSE_2
Definition: Unit.h:610
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition: Unit.h:38
UnitModifierPctType
Definition: Unit.h:162
@ MODIFIER_TYPE_PCT_END
Definition: Unit.h:165
@ TOTAL_PCT
Definition: Unit.h:164
@ BASE_PCT
Definition: Unit.h:163
float GetPctOf(T value, T max)
Definition: Util.h:78
T AddPct(T &base, U pct)
Definition: Util.h:85
T RoundToInterval(T &num, T floor, T ceil)
Definition: Util.h:97
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:528
T ApplyPct(T &base, U pct)
Definition: Util.h:91
T CalculatePct(T base, U pct)
Definition: Util.h:72
@ VEHICLE_SPELL_RIDE_HARDCODED
EncounterType
Definition: ZoneScript.h:36
uint32 GetSpellId() const
Definition: AreaTrigger.h:101
Unit * GetTarget() const
Definition: SpellAuras.h:79
void SetRemoveMode(AuraRemoveMode mode)
Definition: SpellAuras.h:93
uint16 GetSlot() const
Definition: SpellAuras.h:82
bool IsPositive() const
Definition: SpellAuras.h:86
void _HandleEffect(uint8 effIndex, bool apply)
Definition: SpellAuras.cpp:158
Aura * GetBase() const
Definition: SpellAuras.h:80
uint32 GetEffectMask() const
Definition: SpellAuras.h:84
AuraRemoveMode GetRemoveMode() const
Definition: SpellAuras.h:94
bool HasEffect(uint8 effect) const
Definition: SpellAuras.h:85
SpellInfo const * GetSpellInfo() const
AuraType GetAuraType() const
void HandleEffect(AuraApplication *aurApp, uint8 mode, bool apply, AuraEffect const *triggeredBy=nullptr)
bool CanBeRecalculated() const
SpellEffectInfo const & GetSpellEffectInfo() const
uint32 GetId() const
bool IsAffectingSpell(SpellInfo const *spell) const
void ChangeAmount(int32 newAmount, bool mark=true, bool onStackOrReapply=false, AuraEffect const *triggeredBy=nullptr)
int32 GetMiscValueB() const
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)
Definition: SpellAuras.cpp:591
void CallScriptEffectCalcCritChanceHandlers(AuraEffect const *aurEff, AuraApplication const *aurApp, Unit const *victim, float &critChance)
ObjectGuid GetCastId() const
Definition: SpellAuras.h:141
bool IsArea() const
int32 GetMaxDuration() const
Definition: SpellAuras.h:171
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)
Definition: SpellAuras.cpp:349
ApplicationMap const & GetApplicationMap()
Definition: SpellAuras.h:240
void SetStackAmount(uint8 num)
void CallScriptCalcDamageAndHealingHandlers(AuraEffect const *aurEff, AuraApplication const *aurApp, Unit *victim, int32 &damageOrHealing, int32 &flatMod, float &pctMod)
Unit * GetUnitOwner() const
Definition: SpellAuras.h:150
Trinity::IteratorPair< DBStorageIterator< AuraEffect * > > GetAuraEffects()
Definition: SpellAuras.h:316
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
ObjectGuid GetCasterGUID() const
Definition: SpellAuras.h:142
bool HasEffect(uint8 effIndex) const
Definition: SpellAuras.h:231
bool IsRemoved() const
Definition: SpellAuras.h:208
WorldObject * GetOwner() const
Definition: SpellAuras.h:149
bool ModCharges(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool CanStackWith(Aura const *existingAura) const
uint32 GetId() const
Definition: SpellAuras.h:138
int32 CalcDispelChance(Unit const *auraTarget, bool offensive) const
bool IsAppliedOnTarget(ObjectGuid guid) const
int32 GetDuration() const
Definition: SpellAuras.h:176
void UpdateOwner(uint32 diff, WorldObject *owner)
Definition: SpellAuras.cpp:802
void UnregisterSingleTarget()
bool IsDeathPersistent() const
AuraEffect * GetEffect(uint32 index) const
Definition: SpellAuras.cpp:558
Unit * GetCaster() const
Definition: SpellAuras.cpp:542
void SetNeedClientUpdateForTargets() const
void CallScriptEnterLeaveCombatHandlers(AuraApplication const *aurApp, bool isNowInCombat)
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
void SetDuration(int32 duration, bool withMods=false)
Definition: SpellAuras.cpp:926
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
Definition: SpellAuras.cpp:566
uint8 GetStackAmount() const
Definition: SpellAuras.h:192
uint8 GetCharges() const
Definition: SpellAuras.h:183
SpellInfo const * GetSpellInfo() const
Definition: SpellAuras.h:137
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:143
uint32 GetEffectMask() const
void HandleAuraSpecificMods(AuraApplication const *aurApp, Unit *caster, bool apply, bool onReapply)
Difficulty GetCastDifficulty() const
Definition: SpellAuras.h:139
void SetIsSingleTarget(bool val)
Definition: SpellAuras.h:212
virtual void _ApplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
Definition: SpellAuras.cpp:571
bool IsPassive() const
std::unordered_map< ObjectGuid, AuraApplication * > ApplicationMap
Definition: SpellAuras.h:126
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)
Definition: SpellAuras.cpp:621
bool IsSingleTarget() const
Definition: SpellAuras.h:210
void SuppressPvPCombat(UnitFilter *unitFilter=nullptr)
void EndAllPvECombat(UnitFilter *unitFilter=nullptr)
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
void RevalidateCombat()
void Update(uint32 tdiff)
bool HasPvECombat() const
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
void EndAllCombat(UnitFilter *unitFilter=nullptr)
bool HasPvPCombat() const
void EndAllPvPCombat(UnitFilter *unitFilter=nullptr)
static bool IsPlayerMeetingCondition(Player const *player, uint32 conditionId)
virtual void JustUnregisteredDynObject(DynamicObject *)
Definition: CreatureAI.h:123
virtual void JustSummonedGameobject(GameObject *)
Definition: CreatureAI.h:118
virtual void OnSpellClick(Unit *, bool)
Definition: CreatureAI.h:222
virtual void SummonedGameobjectDespawn(GameObject *)
Definition: CreatureAI.h:119
virtual void OnSpellFailed(SpellInfo const *)
Definition: CreatureAI.h:139
virtual void JustUnregisteredAreaTrigger(AreaTrigger *)
Definition: CreatureAI.h:127
virtual void KilledUnit(Unit *)
Definition: CreatureAI.h:108
virtual void JustRegisteredAreaTrigger(AreaTrigger *)
Definition: CreatureAI.h:126
virtual void JustRegisteredDynObject(DynamicObject *)
Definition: CreatureAI.h:122
bool IsTreatedAsRaidUnit() const
Definition: Creature.h:235
bool isWorldBoss() const
Definition: Creature.cpp:2489
CreatureDifficulty const * GetCreatureDifficulty() const
Definition: Creature.h:268
uint16 GetLootMode() const
Definition: Creature.h:317
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > m_personalLoot
Definition: Creature.h:300
void SetLastDamagedTime(time_t val)
Definition: Creature.h:442
bool IsEvadingAttacks() const
Definition: Creature.h:218
uint8 GetLevelForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3114
void AllLootRemovedFromCorpse()
Definition: Creature.cpp:2968
bool CanHaveLoot() const
Definition: Creature.h:295
GuidUnorderedSet const & GetTapList() const
Definition: Creature.h:304
void SetTappedBy(Unit const *unit, bool withGroup=true)
Definition: Creature.cpp:1366
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2420
float GetSpellDamageMod(CreatureClassifications classification) const
Definition: Creature.cpp:1726
CreatureTemplate const * GetCreatureTemplate() const
Definition: Creature.h:266
uint32 GetLootId() const
Definition: Creature.cpp:1353
bool CannotPenetrateWater() const
Definition: Creature.h:150
bool CanEnterWater() const override
Definition: Creature.h:160
void SetDisplayId(uint32 displayId, bool setNative=false) override
Definition: Creature.cpp:3494
void LowerPlayerDamageReq(uint64 unDamage)
Definition: Creature.cpp:1697
bool HasFlag(CreatureStaticFlags flag) const
Definition: Creature.h:472
bool IsFullyLooted() const
Definition: Creature.cpp:1424
void SendAIReaction(AiReaction reactionType)
Definition: Creature.cpp:2526
bool IsAquatic() const
Definition: Creature.h:136
void CallAssistance()
Definition: Creature.cpp:2538
bool IsInEvadeMode() const
Definition: Creature.h:217
CreatureAI * AI() const
Definition: Creature.h:228
static char const * GetBroadcastTextValue(BroadcastTextEntry const *broadcastText, LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false)
Definition: DB2Stores.cpp:2081
static bool IsInArea(uint32 objectAreaId, uint32 areaId)
Definition: DB2Stores.cpp:1980
std::set< MountTypeXCapabilityEntry const *, MountTypeXCapabilityEntryComparator > MountTypeXCapabilitySet
Definition: DB2Stores.h:419
void ResistDamage(uint32 amount)
Definition: Unit.cpp:219
void AbsorbDamage(uint32 amount)
Definition: Unit.cpp:211
ProcFlagsHit m_hitMask
Definition: Unit.h:432
uint32 m_resist
Definition: Unit.h:430
void ModifyDamage(int32 amount)
Definition: Unit.cpp:205
Unit * GetVictim() const
Definition: Unit.h:444
Unit * GetAttacker() const
Definition: Unit.h:443
DamageInfo(Unit *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
Definition: Unit.cpp:135
uint32 GetOriginalDamage() const
Definition: Unit.h:450
uint32 m_block
Definition: Unit.h:431
SpellInfo const * GetSpellInfo() const
Definition: Unit.h:445
void BlockDamage(uint32 amount)
Definition: Unit.cpp:231
WeaponAttackType GetAttackType() const
Definition: Unit.h:448
uint32 GetResist() const
Definition: Unit.h:452
SpellSchoolMask GetSchoolMask() const
Definition: Unit.h:446
uint32 m_absorb
Definition: Unit.h:429
uint32 m_damage
Definition: Unit.h:423
ProcFlagsHit GetHitMask() const
Definition: Unit.cpp:244
uint32 GetDamage() const
Definition: Unit.h:449
uint32 GetAbsorb() const
Definition: Unit.h:451
uint8 GetRemovedCharges() const
Definition: Unit.h:395
bool RollDispel() const
Definition: Unit.cpp:130
int32 _chance
Definition: Unit.h:146
DispelableAura(Aura *aura, int32 dispelChance, uint8 dispelCharges)
Definition: Unit.cpp:123
uint32 GetSpellId() const
Definition: DynamicObject.h:79
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
void KillAllEvents(bool force)
std::multimap< uint64, BasicEvent * > const & GetEvents() const
T_VALUES GetValue(FLAG_TYPE flag) const
Definition: Object.h:573
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:574
static void RemoveCreatureFromGroup(CreatureGroup *group, Creature *member)
ObjectGuid GetOwnerGUID() const override
Definition: GameObject.h:244
uint32 GetSpellId() const
Definition: GameObject.h:251
void Delete()
void SetOwnerGUID(ObjectGuid owner)
Definition: GameObject.h:234
void SetRespawnTime(int32 respawn)
Definition: Group.h:205
uint32 GetMembersCount() const
Definition: Group.h:335
ObjectGuid GetLooterGuid() const
Definition: Group.cpp:1677
GroupReference * GetFirstMember()
Definition: Group.h:333
bool InitStatsForLevel(uint8 level)
Definition: Pet.cpp:839
Definition: Unit.h:459
uint32 _heal
Definition: Unit.h:463
Unit * GetHealer() const
Definition: Unit.h:477
uint32 _effectiveHeal
Definition: Unit.h:465
uint32 GetAbsorb() const
Definition: Unit.h:482
uint32 GetEffectiveHeal() const
Definition: Unit.h:481
SpellInfo const * GetSpellInfo() const
Definition: Unit.h:483
uint32 _absorb
Definition: Unit.h:466
uint32 GetHitMask() const
Definition: Unit.cpp:264
uint32 GetOriginalHeal() const
Definition: Unit.h:480
void SetEffectiveHeal(uint32 amount)
Definition: Unit.h:475
SpellSchoolMask GetSchoolMask() const
Definition: Unit.h:484
void AbsorbHeal(uint32 amount)
Definition: Unit.cpp:254
Unit * GetTarget() const
Definition: Unit.h:478
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition: Unit.cpp:249
uint32 GetHeal() const
Definition: Unit.h:479
uint32 _hitMask
Definition: Unit.h:469
Definition: Item.h:170
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1179
bool IsBroken() const
Definition: Item.h:257
bool HaveLootFor(uint32 loot_id) const
Definition: LootMgr.h:94
void GameObjectRelocation(GameObject *go, float x, float y, float z, float orientation, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1084
bool IsDungeon() const
Definition: Map.cpp:3216
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1052
ZLiquidStatus GetLiquidStatus(PhaseShift const &phaseShift, float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType={}, LiquidData *data=nullptr, float collisionHeight=2.03128f)
Definition: Map.cpp:1698
MapDifficultyEntry const * GetMapDifficulty() const
Definition: Map.cpp:3201
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f)
Definition: Map.cpp:1749
BattlegroundMap * ToBattlegroundMap()
Definition: Map.h:491
Difficulty GetDifficultyID() const
Definition: Map.h:358
MapEntry const * GetEntry() const
Definition: Map.h:229
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition: Map.cpp:1025
Transport * GetTransport(ObjectGuid const &guid)
Definition: Map.cpp:3511
void setDeathState(DeathState s) override
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 MoveFleeing(Unit *enemy, Milliseconds time=0ms, Optional< Scripting::v2::ActionResultSetter< MovementStopReason > > &&scriptResult={})
void PropagateSpeedChange()
void MoveConfused()
void MoveKnockbackFrom(Position const &origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveTargetedHome()
void MoveJumpTo(float angle, float speedXY, float speedZ)
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void DisableTransportPathTransformations()
void SetFacing(float angle)
LowType GetCounter() const
Definition: ObjectGuid.h:296
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:322
bool IsMOTransport() const
Definition: ObjectGuid.h:336
bool IsPlayer() const
Definition: ObjectGuid.h:329
std::string ToString() const
Definition: ObjectGuid.cpp:757
static CreatureModel const * ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=nullptr)
Definition: ObjectMgr.cpp:1611
void SetDynamicFlag(uint32 flag)
Definition: Object.h:205
uint16 m_objectType
Definition: Object.h:442
static Creature * ToCreature(Object *o)
Definition: Object.h:255
bool IsPlayer() const
Definition: Object.h:248
float GetObjectScale() const
Definition: Object.h:200
static Unit * ToUnit(Object *o)
Definition: Object.h:261
Player * ToPlayer()
Definition: Object.h:251
ObjectGuid const & GetGUID() const
Definition: Object.h:196
bool IsInWorld() const
Definition: Object.h:190
bool HasDynamicFlag(uint32 flag) const
Definition: Object.h:204
void RemoveUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:340
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData *data, UF::UpdateFieldFlag flags, Player const *target) const
Definition: Object.cpp:232
TypeID GetTypeId() const
Definition: Object.h:209
virtual void DestroyForPlayer(Player *target) const
Definition: Object.cpp:281
CreateObjectBits m_updateFlag
Definition: Object.h:445
void SetUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:333
virtual void ClearUpdateMask(bool remove)
Definition: Object.cpp:854
void SetUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type value)
Definition: Object.h:326
uint32 GetEntry() const
Definition: Object.h:197
bool IsCreature() const
Definition: Object.h:254
UF::UpdateFieldHolder m_values
Definition: Object.h:303
Creature * ToCreature()
Definition: Object.h:257
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:195
WowCS::EntityFragmentsHolder m_entityFragments
Definition: Object.h:446
virtual void SetObjectScale(float scale)
Definition: Object.h:201
void ForceUpdateFieldChange(UF::UpdateFieldSetter< T > const &)
Definition: Object.h:307
TypeID m_objectTypeId
Definition: Object.h:444
static Player * ToPlayer(Object *o)
Definition: Object.h:249
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldSetter< T > setter, float percent, bool apply)
Definition: Object.h:404
Optional< uint32 > GetCurrentActivePetIndex() const
Definition: PetDefines.h:188
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition: PetDefines.h:169
void SetCurrentActivePetIndex(uint32 index)
Definition: PetDefines.h:189
Definition: Pet.h:40
void FillPetInfo(PetStable::PetInfo *petInfo, Optional< ReactStates > forcedReactState={}) const
Definition: Pet.cpp:544
void SetGroupUpdateFlag(uint32 flag)
Definition: Pet.cpp:1834
std::string GetDebugInfo() const override
Definition: Pet.cpp:1943
bool CreateBaseAtCreatureInfo(CreatureTemplate const *cinfo, Unit *owner)
Definition: Pet.cpp:801
bool CreateBaseAtCreature(Creature *creature)
Definition: Pet.cpp:768
bool isControlled() const
Definition: Pet.h:53
void InitPetCreateSpells()
Definition: Pet.cpp:1602
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
void StopCastingBindSight() const
Definition: Player.cpp:26575
bool HaveAtClient(Object const *u) const
Definition: Player.cpp:24157
void SetClientControl(Unit *target, bool allowMove)
Definition: Player.cpp:26185
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2156
void SendAttackSwingCancelAttack() const
Definition: Player.cpp:21620
void AddPetToUpdateFields(PetStable::PetInfo const &pet, PetSaveMode slot, PetStableFlags flags)
Definition: Player.cpp:29205
void SetGroupUpdateFlag(uint32 flag)
Definition: Player.h:2716
void DuelComplete(DuelCompleteType type)
Definition: Player.cpp:7801
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6322
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6050
void SendAutoRepeatCancel(Unit *target)
Definition: Player.cpp:21633
PetStable & GetOrInitPetStable()
Definition: Player.cpp:29197
float GetRatingBonusValue(CombatRating cr) const
Definition: Player.cpp:5284
void CharmSpellInitialize()
Definition: Player.cpp:22359
void UpdatePvPState(bool onlyFFA=false)
Definition: Player.cpp:23748
bool InBattleground() const
Definition: Player.h:2496
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition: Player.cpp:4709
void PetSpellInitialize()
Definition: Player.cpp:22247
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat.
Definition: Player.h:2159
void SetFallInformation(uint32 time, float z)
Definition: Player.cpp:27133
void SendRemoveControlBar() const
Definition: Player.cpp:22399
WorldSession * GetSession() const
Definition: Player.h:2195
OutdoorPvP * GetOutdoorPvP() const
Definition: Player.cpp:25885
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition: Player.cpp:8699
PlayerSpellMap const & GetSpellMap() const
Definition: Player.h:1992
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:27228
void StopCastingCharm()
Definition: Player.cpp:22045
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition: Player.cpp:1229
Battleground * GetBattleground() const
Definition: Player.cpp:25401
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition: Player.cpp:5345
bool IsGameMaster() const
Definition: Player.h:1247
std::array< uint8, MAX_MOVE_TYPE > m_forced_speed_changes
Definition: Player.h:2631
void PossessSpellInitialize()
Definition: Player.cpp:22286
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition: Player.cpp:9694
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2708
std::unique_ptr< DuelInfo > duel
Definition: Player.h:2066
uint8 GetSubGroup() const
Definition: Player.h:2714
void VehicleSpellInitialize()
Definition: Player.cpp:22312
Team GetEffectiveTeam() const
Definition: Player.h:2338
void SetFactionForRace(uint8 race)
Definition: Player.cpp:6521
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition: Player.cpp:21765
void ResummonPetTemporaryUnSummonedIfAny()
Definition: Player.cpp:27640
void UpdatePvP(bool state, bool override=false)
Definition: Player.cpp:23791
bool IsInSameGroupWith(Player const *p) const
Definition: Player.cpp:2149
ProcEventInfo(Unit *actor, Unit *actionTarget, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:269
DamageInfo * _damageInfo
Definition: Unit.h:522
SpellSchoolMask GetSchoolMask() const
Definition: Unit.cpp:291
HealInfo * _healInfo
Definition: Unit.h:523
Spell const * GetProcSpell() const
Definition: Unit.h:511
SpellInfo const * GetSpellInfo() const
Definition: Unit.cpp:280
Spell * _spell
Definition: Unit.h:521
Derived * next()
Definition: Reference.h:84
Mechanics Mechanic
Definition: SpellInfo.h:225
AuraType ApplyAuraName
Definition: SpellInfo.h:215
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:644
SpellEffectName Effect
Definition: SpellInfo.h:214
float BonusCoefficientFromAP
Definition: SpellInfo.h:235
float BonusCoefficient
Definition: SpellInfo.h:222
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition: SpellInfo.h:237
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void ResetCooldowns(Predicate &&predicate, bool update=false)
Definition: SpellHistory.h:154
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false, Optional< Duration > forcedCooldown={})
DiminishingLevels GetDiminishingReturnsMaxLevel() const
Definition: SpellInfo.cpp:3359
Mechanics GetEffectMechanic(SpellEffIndex effIndex) const
Definition: SpellInfo.cpp:2570
SpellInfo const * GetFirstRankSpell() const
Definition: SpellInfo.cpp:4339
bool HasEffect(SpellEffectName effect) const
Definition: SpellInfo.cpp:1458
std::unordered_set< uint32 > Labels
Definition: SpellInfo.h:413
uint64 GetAllEffectsMechanicMask() const
Definition: SpellInfo.cpp:2532
bool IsRequiringDeadTarget() const
Definition: SpellInfo.cpp:1735
uint32 const Id
Definition: SpellInfo.h:322
EnumFlag< SpellAuraInterruptFlags2 > AuraInterruptFlags2
Definition: SpellInfo.h:371
bool IsGroupBuff() const
Definition: SpellInfo.cpp:1757
bool IsDeathPersistent() const
Definition: SpellInfo.cpp:1730
bool IsCooldownStartedOnEvent() const
Definition: SpellInfo.cpp:1721
bool IsPassive() const
Definition: SpellInfo.cpp:1659
uint32 Mechanic
Definition: SpellInfo.h:326
bool HasAnyAuraInterruptFlag() const
Definition: SpellInfo.cpp:1532
bool IsStackableOnOneSlotWithDifferentCasters() const
Definition: SpellInfo.cpp:1715
uint32 GetDispelMask() const
Definition: SpellInfo.cpp:2581
SpellSpecificType GetSpellSpecific() const
Definition: SpellInfo.cpp:2689
DiminishingReturnsType GetDiminishingReturnsGroupType() const
Definition: SpellInfo.cpp:3354
uint32 Dispel
Definition: SpellInfo.h:325
bool IsMultiSlotAura() const
Definition: SpellInfo.cpp:1710
int32 GetMaxDuration() const
Definition: SpellInfo.cpp:3865
int32 GetDiminishingReturnsLimitDuration() const
Definition: SpellInfo.cpp:3364
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
Definition: SpellInfo.cpp:3349
uint32 SchoolMask
Definition: SpellInfo.h:411
uint32 CasterAuraState
Definition: SpellInfo.h:351
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
Definition: SpellInfo.cpp:2226
flag128 SpellFamilyFlags
Definition: SpellInfo.h:407
WeaponAttackType GetAttackType() const
Definition: SpellInfo.cpp:1833
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2527
AuraStateType GetAuraState() const
Definition: SpellInfo.cpp:2600
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
Definition: SpellInfo.cpp:2557
uint32 Attributes
Definition: SpellInfo.h:327
bool IsPassiveStackableWithRanks() const
Definition: SpellInfo.cpp:1705
uint32 MaxAffectedTargets
Definition: SpellInfo.h:405
int32 GetDuration() const
Definition: SpellInfo.cpp:3858
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:580
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
Definition: SpellInfo.cpp:2421
bool CanPierceImmuneAura(SpellInfo const *auraSpellInfo) const
Definition: SpellInfo.cpp:1931
bool IsPositive() const
Definition: SpellInfo.cpp:1781
uint32 DmgClass
Definition: SpellInfo.h:408
bool IsRangedWeaponSpell() const
Definition: SpellInfo.cpp:1806
EnumFlag< SpellAuraInterruptFlags > AuraInterruptFlags
Definition: SpellInfo.h:370
bool HasAura(AuraType aura) const
Definition: SpellInfo.cpp:1467
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const
Definition: SpellInfo.h:470
bool HasLabel(uint32 labelId) const
Definition: SpellInfo.cpp:5010
uint32 SpellFamilyName
Definition: SpellInfo.h:406
bool IsSingleTarget() const
Definition: SpellInfo.cpp:1949
static CreatureImmunities const * GetCreatureImmunities(int32 creatureImmunitiesId)
Definition: SpellMgr.cpp:686
Definition: Spell.h:262
SpellInfo const * GetSpellInfo() const
Definition: Spell.h:670
void CallScriptCalcDamageHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:9030
bool IsInterruptable() const
Definition: Spell.h:651
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition: Spell.cpp:5821
bool IsProcDisabled() const
Definition: Spell.cpp:8365
int32 GetCastTime() const
Definition: Spell.h:628
std::string GetDebugInfo() const
Definition: Spell.cpp:9297
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:4734
uint32 getState() const
Definition: Spell.h:527
int32 GetProcChainLength() const
Definition: Spell.h:647
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition: Spell.cpp:9093
CurrentSpellTypes GetCurrentContainer() const
Definition: Spell.cpp:8222
void cancel()
Definition: Spell.cpp:3606
void SendChannelUpdate(uint32 time, Optional< SpellCastResult > result={})
Definition: Spell.cpp:5286
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3425
void CallScriptCalcHealingHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:9042
Spell ** m_selfContainer
Definition: Spell.h:683
void SetReferencedFromCurrent(bool yes)
Definition: Spell.h:650
UsedSpellMods m_appliedMods
Definition: Spell.h:623
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition: Spell.cpp:9018
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition: Spell.cpp:4386
virtual void UnSummon(uint32 msTime=0)
SummonPropertiesEntry const *const m_Properties
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:39
virtual ObjectGuid GetTransportGUID() const =0
void CalculatePassengerPosition(float &x, float &y, float &z, float *o=nullptr) const override
This method transforms supplied transport offsets into global coordinates.
Definition: Transport.h:76
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition: IteratorPair.h:32
constexpr end_iterator end() const
Definition: IteratorPair.h:39
constexpr iterator begin() const
Definition: IteratorPair.h:38
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UnitAI.h:50
virtual void OnCharmed(bool isNew)
Definition: UnitAI.cpp:49
Definition: Unit.h:631
float GetUnitMissChance() const
Definition: Unit.cpp:2783
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition: Unit.cpp:12517
void SetCannotTurn(bool apply)
Definition: Unit.cpp:8359
bool SetCanDoubleJump(bool enable)
Definition: Unit.cpp:13548
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:798
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition: Unit.cpp:9420
Unit * GetCharmed() const
Definition: Unit.h:1203
void ClearUnitState(uint32 f)
Definition: Unit.h:740
void OutDebugInfo() const
Definition: Unit.cpp:12914
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition: Unit.cpp:680
void RemoveAreaTrigger(uint32 spellId)
Definition: Unit.cpp:5414
bool IsStopped() const
Definition: Unit.h:1699
void SetFlightCapabilityID(int32 flightCapabilityId, bool clientUpdate)
Definition: Unit.cpp:8790
bool IsVehicle() const
Definition: Unit.h:750
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
Definition: Unit.cpp:8029
void SetMinion(Minion *minion, bool apply)
Definition: Unit.cpp:6153
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition: Unit.h:643
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:8484
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1158
bool IsWithinMeleeRange(Unit const *obj) const
Definition: Unit.h:706
void ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction={}, ObjectGuid transportGuid=ObjectGuid::Empty)
Definition: Unit.cpp:13689
void SetImmuneToAll(bool apply, bool keepCombat)
Definition: Unit.cpp:8292
bool IsCharmed() const
Definition: Unit.h:1227
void SetImmuneToPC(bool apply, bool keepCombat)
Definition: Unit.cpp:8305
bool m_duringRemoveFromWorld
Definition: Unit.h:2010
float GetBoundingRadius() const
Definition: Unit.h:703
void KnockbackFrom(Position const &origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
Definition: Unit.cpp:12244
int32 SpellDamageBonusDone(Unit *victim, SpellInfo const *spellProto, int32 pdamage, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, uint32 stack=1, Spell *spell=nullptr, AuraEffect const *aurEff=nullptr) const
Definition: Unit.cpp:6717
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3674
Vehicle * GetVehicle() const
Definition: Unit.h:1756
EnumFlag< SpellAuraInterruptFlags2 > m_interruptMask2
Definition: Unit.h:1911
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition: Unit.cpp:701
void SetVisible(bool x)
Definition: Unit.cpp:8555
virtual bool IsMovementPreventedByCasting() const
Definition: Unit.cpp:3181
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3878
virtual void UpdateResistances(uint32 school)
Definition: Unit.cpp:9645
bool HealthAbovePct(int32 pct) const
Definition: Unit.h:790
void DeleteCharmInfo()
Definition: Unit.cpp:10140
void RemoveGameObject(GameObject *gameObj, bool del)
Definition: Unit.cpp:5307
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition: Unit.cpp:8372
bool IsHunterPet() const
Definition: Unit.h:748
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1333
uint32 GetSchoolImmunityMask() const
Definition: Unit.cpp:7603
std::unique_ptr< SpellHistory > _spellHistory
Definition: Unit.h:2022
void UpdateAttackTimeField(WeaponAttackType att)
Definition: Unit.cpp:10698
float GetHealthPct() const
Definition: Unit.h:792
float m_baseSpellCritChance
Definition: Unit.h:1507
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition: Unit.h:1579
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5918
int32 MeleeDamageBonusTaken(Unit *attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition: Unit.cpp:7920
bool HasExtraUnitMovementFlag(uint32 f) const
Definition: Unit.h:1712
void AIUpdateTick(uint32 diff)
Definition: Unit.cpp:9909
void JumpTo(float speedXY, float speedZ, float angle, Optional< Position > dest={})
Definition: Unit.cpp:12389
virtual void RecalculateObjectScale()
Definition: Unit.cpp:10524
void SetHealth(uint64 val)
Definition: Unit.cpp:9727
Unit * m_unitMovedByMe
Definition: Unit.h:1924
virtual MovementGeneratorType GetDefaultMovementType() const
Definition: Unit.cpp:10428
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
Definition: Unit.cpp:745
AuraList m_removedAuras
Definition: Unit.h:1902
void SetFacingToPoint(Position const &point, bool force=true)
Definition: Unit.cpp:13088
bool SetCanAdvFly(bool enable)
Definition: Unit.cpp:13610
uint32 GetUnitMovementFlags() const
Definition: Unit.h:1707
LiquidTypeEntry const * _lastLiquid
Definition: Unit.h:1940
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7216
void _UpdateAutoRepeatSpell()
Definition: Unit.cpp:2966
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition: Unit.cpp:14012
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition: Unit.cpp:12233
float GetTotalAuraModValue(UnitMods unitMod) const
Definition: Unit.cpp:9592
AreaTriggerList m_areaTrigger
Definition: Unit.h:1894
bool IsInteractionAllowedInCombat() const
Definition: Unit.h:1062
void RestoreDisabledAI()
Definition: Unit.cpp:9963
void Heartbeat() override
Definition: Unit.cpp:502
int32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype) const
Definition: Unit.cpp:7385
void RemoveAllControlled()
Definition: Unit.cpp:6519
Pet * ToPet()
Definition: Unit.h:1794
ObjectGuid GetDemonCreatorGUID() const
Definition: Unit.h:1194
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition: Unit.h:1025
void RemoveAurasByShapeShift()
Definition: Unit.cpp:4263
float GetTotalStatValue(Stats stat) const
Definition: Unit.cpp:9576
void SetPlayHoverAnim(bool enable, bool sendUpdate=true)
Definition: Unit.cpp:13815
std::unique_ptr< MotionMaster > i_motionMaster
Definition: Unit.h:1931
void SetUnitFlag3(UnitFlags3 flags)
Definition: Unit.h:852
void SetGender(Gender gender)
Definition: Unit.h:764
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition: Unit.cpp:2856
bool IsContestedGuard() const
Definition: Unit.cpp:11986
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition: Unit.h:2006
void UpdateUnitMod(UnitMods unitMod)
Definition: Unit.cpp:9431
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition: Unit.cpp:9529
float GetSpeed(UnitMoveType mtype) const
Definition: Unit.cpp:8719
bool SetFall(bool enable)
Definition: Unit.cpp:13185
void _UnregisterDynObject(DynamicObject *dynObj)
Definition: Unit.cpp:5226
bool m_canModifyStats
Definition: Unit.h:1916
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3751
void UpdateObjectVisibility(bool forced=true) override
Definition: Unit.cpp:12220
int64 ModifyHealth(int64 val)
Definition: Unit.cpp:8386
std::array< uint32, MAX_REACTIVE > m_reactiveTimer
Definition: Unit.h:1933
void AddExtraUnitMovementFlag(uint32 f)
Definition: Unit.h:1710
std::shared_ptr< UnitAI > i_AI
Definition: Unit.h:2000
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition: Unit.cpp:14147
void SetCurrentCastSpell(Spell *pSpell)
Definition: Unit.cpp:3001
bool _isCombatDisallowed
Definition: Unit.h:2027
void SetFullHealth()
Definition: Unit.h:798
void TriggerOnHealthChangeAuras(uint64 oldVal, uint64 newVal)
Definition: Unit.cpp:8453
void SetMinionGUID(ObjectGuid guid)
Definition: Unit.h:1187
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo) const
Definition: Unit.cpp:6808
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition: Unit.cpp:10556
Diminishing m_Diminishing
Definition: Unit.h:1988
void SetHoverHeight(float hoverHeight)
Definition: Unit.h:1142
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10484
void FinishSpell(CurrentSpellTypes spellType, SpellCastResult result=SPELL_CAST_OK)
Definition: Unit.cpp:3109
void EnergizeBySpell(Unit *victim, SpellInfo const *spellInfo, int32 damage, Powers powerType)
Definition: Unit.cpp:6704
void SetInitialPowerValue(Powers powerType)
Definition: Unit.cpp:5658
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition: Unit.cpp:12855
std::array< Spell *, CURRENT_MAX_SPELL > m_currentSpells
Definition: Unit.h:1898
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition: Unit.cpp:3638
virtual void OnPhaseChange()
Definition: Unit.cpp:12216
void SetConfused(bool apply)
Definition: Unit.cpp:11501
void _UpdateSpells(uint32 time)
Definition: Unit.cpp:2904
ThreatManager & GetThreatManager()
Definition: Unit.h:1073
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition: Unit.h:879
void AddToWorld() override
Definition: Unit.cpp:9987
virtual float GetArmorMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:805
void RestoreFaction()
Definition: Unit.cpp:11801
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition: Unit.cpp:8057
virtual void AtExitCombat()
Definition: Unit.cpp:9016
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition: Unit.cpp:3523
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4756
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition: Unit.h:1055
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13970
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition: Unit.cpp:10423
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition: Unit.cpp:763
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition: Unit.cpp:4502
void SetControlled(bool apply, UnitState state)
Definition: Unit.cpp:11295
uint8 GetClass() const
Definition: Unit.h:760
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition: Unit.cpp:9608
void SetStunned(bool apply)
Definition: Unit.cpp:11392
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition: Unit.h:1491
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition: Unit.cpp:9628
uint32 m_state
Definition: Unit.h:1986
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition: Unit.cpp:12404
bool CanUseAttackType(uint8 attacktype) const
Definition: Unit.cpp:2552
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition: Unit.cpp:664
Player * GetDemonCreatorPlayer() const
Definition: Unit.cpp:6103
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition: Unit.cpp:5384
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition: Unit.cpp:4748
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition: Unit.cpp:3166
uint32 GetMountDisplayId() const
Definition: Unit.h:908
void UpdateAllDamageDoneMods()
Definition: Unit.cpp:9523
Vehicle * m_vehicle
Definition: Unit.h:1936
void RemoveVisibleAura(AuraApplication *aurApp)
Definition: Unit.cpp:718
Totem * ToTotem()
Definition: Unit.h:1797
int64 GetHealthGain(int64 dVal)
Definition: Unit.cpp:8428
Creature * GetVehicleCreatureBase() const
Definition: Unit.cpp:11885
std::unique_ptr< CharmInfo > m_charmInfo
Definition: Unit.h:1928
void UpdateDisplayPower()
Definition: Unit.cpp:5716
float GetCollisionHeight() const override
Definition: Unit.cpp:14171
void AddExtraUnitMovementFlag2(uint32 f)
Definition: Unit.h:1716
void RemoveAllGameObjects()
Definition: Unit.cpp:5371
static void DealHeal(HealInfo &healInfo)
Definition: Unit.cpp:6430
bool isPossessedByPlayer() const
Definition: Unit.cpp:6546
void SendClearTarget()
Definition: Unit.cpp:12956
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition: Unit.h:641
void _RegisterDynObject(DynamicObject *dynObj)
Definition: Unit.cpp:5219
void UpdateSpeed(UnitMoveType mtype)
Definition: Unit.cpp:8565
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition: Unit.cpp:777
bool IsPolymorphed() const
Definition: Unit.cpp:10511
void CancelTravelShapeshiftForm(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition: Unit.h:1497
bool IsAreaSpiritHealer() const
Definition: Unit.h:1012
void PlayOneShotAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10913
float m_weaponDamage[MAX_ATTACK][2]
Definition: Unit.h:1915
ShapeshiftForm GetShapeshiftForm() const
Definition: Unit.h:1494
void SetFaction(uint32 faction) override
Definition: Unit.h:868
virtual void SetPvP(bool state)
Definition: Unit.cpp:11994
ObjectGuid GetOwnerGUID() const override
Definition: Unit.h:1182
uint64 GetMechanicImmunityMask() const
Definition: Unit.cpp:7623
void CancelShapeshiftForm(bool onlyTravelShapeshiftForm=false, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition: Unit.cpp:9256
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition: Unit.cpp:10656
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition: Unit.cpp:3225
float GetCombatRatingReduction(CombatRating cr) const
Definition: Unit.cpp:12274
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition: Unit.cpp:3930
void RemoveExtraUnitMovementFlag(uint32 f)
Definition: Unit.h:1711
bool SetEnableFullSpeedTurning(bool enable)
Definition: Unit.cpp:13448
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition: Unit.cpp:2065
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13975
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:1165
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK) const =0
Unit * GetVehicleRoot() const
Definition: Unit.cpp:11869
void SetCantProc(bool apply)
Definition: Unit.cpp:10776
Unit * GetCharmer() const
Definition: Unit.h:1200
void SetSpeed(UnitMoveType mtype, float newValue)
Definition: Unit.cpp:8724
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, Aura *except=nullptr) const
Definition: Unit.cpp:3735
int32 m_procChainLength
Definition: Unit.h:1885
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition: Unit.cpp:9400
Unit * getAttackerForHelper() const
Definition: Unit.cpp:5738
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:648
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2743
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:9800
void TriggerOnPowerChangeAuras(Powers power, int32 oldVal, int32 newVal)
Definition: Unit.cpp:9862
void SendMeleeAttackStart(Unit *victim)
Definition: Unit.cpp:2504
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition: Unit.cpp:10825
void UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
Definition: Unit.cpp:8812
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition: Unit.h:1937
bool IsInDisallowedMountForm() const
Definition: Unit.cpp:9294
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition: Unit.cpp:9367
bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7511
VisibleAuraContainer m_visibleAuras
Definition: Unit.h:1918
UnitPVPStateFlags GetPvpFlags() const
Definition: Unit.h:875
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition: Unit.cpp:9493
void _removeAttacker(Unit *pAttacker)
Definition: Unit.cpp:5733
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition: Unit.cpp:5557
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4647
std::forward_list< AuraApplication * > AuraApplicationList
Definition: Unit.h:650
uint32 GetTransformSpell() const
Definition: Unit.h:1607
void RemoveAllAurasExceptType(AuraType type)
Definition: Unit.cpp:4446
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1275
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
Definition: Unit.cpp:2452
uint32 _lastExtraAttackSpell
Definition: Unit.h:2005
void SetAnimTier(AnimTier animTier, bool notifyClient=true)
Definition: Unit.cpp:10498
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition: Unit.cpp:1834
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3151
virtual bool CanFly() const =0
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition: Unit.cpp:12049
Unit * GetVehicleBase() const
Definition: Unit.cpp:11864
bool haveOffhandWeapon() const
Definition: Unit.cpp:525
MotionMaster * GetMotionMaster()
Definition: Unit.h:1695
bool SetFeatherFall(bool enable)
Definition: Unit.cpp:13300
bool IsPet() const
Definition: Unit.h:747
Powers GetPowerType() const
Definition: Unit.h:807
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:841
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition: Unit.cpp:1656
void _addAttacker(Unit *pAttacker)
Definition: Unit.cpp:5728
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsHit hitMask, WeaponAttackType attType)
Definition: Unit.cpp:10234
bool _instantCast
Definition: Unit.h:2011
void Dismount()
Definition: Unit.cpp:8104
std::array< ObjectGuid, MAX_GAMEOBJECT_SLOT > m_ObjectSlot
Definition: Unit.h:1492
void SetCharm(Unit *target, bool apply)
Definition: Unit.cpp:6349
void SetMovedUnit(Unit *target)
Definition: Unit.cpp:10149
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1202
void SetCreatedBySpell(int32 spellId)
Definition: Unit.h:856
bool SetHover(bool enable, bool updateAnimTier=true)
Definition: Unit.cpp:13338
bool CanDualWield() const
Definition: Unit.h:699
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3121
void UpdateInterruptMask()
Definition: Unit.cpp:725
void StartReactiveTimer(ReactiveType reactive)
Definition: Unit.h:1737
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition: Unit.cpp:9112
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: Unit.cpp:10081
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition: Unit.cpp:13071
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition: Unit.cpp:10460
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:12002
bool HasInterruptFlag(SpellAuraInterruptFlags flags) const
Definition: Unit.h:1589
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition: Unit.cpp:4533
bool isAttackingPlayer() const
Definition: Unit.cpp:5954
void AtEndOfEncounter(EncounterType type)
Definition: Unit.cpp:568
virtual void AtEnterCombat()
Definition: Unit.cpp:8993
UnitAIStack i_AIs
Definition: Unit.h:1999
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition: Unit.cpp:10687
std::unique_ptr< MovementForces > _movementForces
Definition: Unit.h:2024
int32 GetMaxNegativeAuraModifier(AuraType auraType) const
Definition: Unit.cpp:5013
void UpdateSplineMovement(uint32 t_diff)
Definition: Unit.cpp:589
uint32 GetDamageReduction(uint32 damage) const
Definition: Unit.h:963
std::array< float, MAX_STATS > m_floatStatPosBuff
Definition: Unit.h:1876
void SetUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:847
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:846
bool CanFreeMove() const
Definition: Unit.cpp:9704
std::string GetDebugInfo() const override
Definition: Unit.cpp:14212
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition: Unit.h:638
virtual bool IsLoading() const
Definition: Unit.h:1791
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition: Unit.cpp:6041
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition: Unit.cpp:3220
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition: Unit.h:1913
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition: Unit.cpp:8328
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition: Unit.cpp:10448
void SetPetNameTimestamp(uint32 timestamp)
Definition: Unit.h:1237
bool IsSplineEnabled() const
Definition: Unit.cpp:13851
std::array< uint32, MAX_ATTACK > m_baseAttackSpeed
Definition: Unit.h:1509
void RemoveAllAurasRequiringDeadTarget()
Definition: Unit.cpp:4425
void UpdateAuraForGroup()
Definition: Unit.cpp:10761
Vignettes::VignetteData const * GetVignette() const
Definition: Unit.h:1853
void UpdateReactives(uint32 p_time)
Definition: Unit.cpp:10622
bool IsAlive() const
Definition: Unit.h:1176
virtual bool CanApplyResilience() const
Definition: Unit.cpp:12143
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition: Unit.cpp:4845
float m_modRangedHitChance
Definition: Unit.h:1505
float GetCombatReach() const override
Definition: Unit.h:701
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition: Unit.cpp:9032
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition: Unit.cpp:1733
DeathState m_deathState
Definition: Unit.h:1882
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition: Unit.cpp:10719
void SetBonusResistanceMod(SpellSchools school, int32 val)
Definition: Unit.h:781
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9791
uint32 m_unitTypeMask
Definition: Unit.h:1939
void StopMoving()
Definition: Unit.cpp:10433
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition: Unit.h:642
int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:5048
void RemoveAllAreaTriggers()
Definition: Unit.cpp:5441
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6682
void AddPlayerToVision(Player *player)
Definition: Unit.cpp:6616
void RemoveNpcFlag(NPCFlags flags)
Definition: Unit.h:993
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6663
int32 GetMaxPositiveAuraModifier(AuraType auraType) const
Definition: Unit.cpp:5008
GameObject * GetGameObject(uint32 spellId) const
Definition: Unit.cpp:5270
int32 GetFlightCapabilityID() const
Definition: Unit.h:1683
virtual ~Unit()
Definition: Unit.cpp:392
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12622
uint32 m_removedAurasCount
Definition: Unit.h:1904
void RemoveAllAurasOnDeath()
Definition: Unit.cpp:4402
uint32 m_movementCounter
Incrementing counter used in movement packets.
Definition: Unit.h:1982
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition: Unit.cpp:5447
bool IsStandState() const
Definition: Unit.cpp:10478
TempSummon * ToTempSummon()
Definition: Unit.h:1800
bool IsGravityDisabled() const
Definition: Unit.h:1144
CharmInfo * GetCharmInfo()
Definition: Unit.h:1233
void AtStartOfEncounter(EncounterType type)
Definition: Unit.cpp:543
bool SetCanTransitionBetweenSwimAndFly(bool enable)
Definition: Unit.cpp:13482
bool SetDisableInertia(bool disable)
Definition: Unit.cpp:13579
ControlList m_Controlled
Definition: Unit.h:1223
bool IsInCombatWith(Unit const *who) const
Definition: Unit.h:1054
void DisableSpline()
Definition: Unit.cpp:653
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1207
int32 GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition: Unit.cpp:2529
int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5078
void RemoveUnitFlag3(UnitFlags3 flags)
Definition: Unit.h:853
AuraMap::iterator m_auraUpdateIterator
Definition: Unit.h:1903
UnitAI * GetAI() const
Definition: Unit.h:664
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:6488
void DestroyForPlayer(Player *target) const override
Definition: Unit.cpp:13869
ObjectGuid _lastDamagedTargetGuid
Definition: Unit.h:2007
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:7027
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition: Unit.cpp:13125
void CancelSpellMissiles(uint32 spellId, bool reverseMissile=false, bool abortSpell=false)
Definition: Unit.cpp:12113
void RemoveAurasWithAttribute(uint32 flags)
Definition: Unit.cpp:4076
void RemoveAllFollowers()
Definition: Unit.cpp:8932
virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed)
Definition: Unit.cpp:9068
void UpdateMountCapability()
Definition: Unit.cpp:8246
void _DeleteRemovedAuras()
Definition: Unit.cpp:2893
Player * GetPlayerMovingMe() const
Definition: Unit.h:1244
void CancelMountAura(bool force=false)
Definition: Unit.cpp:8137
void _ApplyAura(AuraApplication *aurApp, uint32 effMask)
Definition: Unit.cpp:3470
void SetUninteractible(bool apply)
Definition: Unit.cpp:8351
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition: Unit.cpp:6564
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition: Unit.cpp:10692
virtual bool HasSpell(uint32) const
Definition: Unit.h:1079
virtual bool IsAffectedByDiminishingReturns() const
Definition: Unit.h:682
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition: Unit.h:646
int32 GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:5018
void AddUnitState(uint32 f)
Definition: Unit.h:738
static void ApplyResilience(Unit const *victim, int32 *damage)
Definition: Unit.cpp:12148
float GetTotalAuraMultiplier(AuraType auraType) const
Definition: Unit.cpp:5003
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition: Unit.cpp:8071
void SetSheath(SheathState sheathed)
Definition: Unit.cpp:5721
bool IsOnVehicle(Unit const *vehicle) const
Definition: Unit.cpp:11859
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition: Unit.cpp:5538
bool isInAccessiblePlaceFor(Creature const *c) const
Definition: Unit.cpp:3230
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition: Unit.h:1208
Gender GetGender() const
Definition: Unit.h:763
int32 GetMinPower(Powers power) const
Definition: Unit.h:814
virtual void SetInteractionAllowedInCombat(bool interactionAllowed)
Definition: Unit.cpp:9078
Unit * EnsureVictim() const
Definition: Unit.h:724
int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5088
uint32 getAttackTimer(WeaponAttackType type) const
Definition: Unit.h:696
void RefreshAI()
Definition: Unit.cpp:9941
bool IsDuringRemoveFromWorld() const
Definition: Unit.h:1792
void SendPlaySpellVisual(Unit *target, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime=false, float launchDelay=0.0f)
Definition: Unit.cpp:12058
bool m_ControlledByPlayer
Definition: Unit.h:1873
void SetFeared(bool apply)
Definition: Unit.cpp:11465
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1212
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition: Unit.cpp:4857
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition: Unit.cpp:4042
virtual void UpdateDamagePhysical(WeaponAttackType attType)
Definition: StatSystem.cpp:64
bool IsPlayingHoverAnim() const
Definition: Unit.h:1139
void _ApplyAllAuraStatMods()
Definition: Unit.cpp:4527
bool SetMoveCantSwim(bool cantSwim)
Definition: Unit.cpp:13641
void SetBattlePetCompanionNameTimestamp(uint32 timestamp)
Definition: Unit.h:1258
bool IsImmunedToAuraPeriodicTick(WorldObject const *caster, SpellInfo const *spellInfo, SpellEffectInfo const *spellEffectInfo=nullptr) const
Definition: Unit.cpp:7771
uint32 GetCreatureType() const
Definition: Unit.cpp:9227
int32 RewardRage(uint32 baseRage)
Definition: Unit.cpp:12863
void AddGameObject(GameObject *gameObj)
Definition: Unit.cpp:5286
void InterruptMovementBasedAuras()
Definition: Unit.cpp:643
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7705
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition: Unit.cpp:13890
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition: Unit.cpp:4792
bool IsThreatened() const
Definition: Unit.cpp:8367
void SendSetVehicleRecId(uint32 vehicleId)
Definition: Unit.cpp:13672
bool SetSwim(bool enable)
Definition: Unit.cpp:13201
void SetEmoteState(Emote emote)
Definition: Unit.h:861
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition: Unit.cpp:12791
DynObjectList m_dynObj
Definition: Unit.h:1888
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition: Unit.cpp:5038
PositionUpdateInfo _positionUpdateInfo
Definition: Unit.h:2025
void SetPvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:877
virtual void UpdateNearbyPlayersInteractions()
Definition: Unit.cpp:9089
AuraApplicationList m_interruptableAuras
Definition: Unit.h:1908
void SetResistance(SpellSchools school, int32 val)
Definition: Unit.h:780
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5068
uint32 GetDisplayId() const
Definition: Unit.h:1600
void SendCancelSpellVisualKit(uint32 id)
Definition: Unit.cpp:12105
uint32 GetVirtualItemId(uint32 slot) const
Definition: Unit.cpp:13996
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:1791
void SendSpellDamageImmune(Unit *target, uint32 spellId, bool isPeriodic)
Definition: Unit.cpp:5547
void ModifyAuraState(AuraStateType flag, bool apply)
Definition: Unit.cpp:5985
bool IsAIEnabled() const
Definition: Unit.h:662
Unit * GetUnitBeingMoved() const
Definition: Unit.h:1242
EnumFlag< SpellOtherImmunity > GetSpellOtherImmunityMask() const
Definition: Unit.cpp:7633
uint32 GetAuraCount(uint32 spellId) const
Definition: Unit.cpp:4717
UnitAI * GetTopAI() const
Definition: Unit.h:670
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition: Unit.cpp:2316
bool isPossessing() const
Definition: Unit.cpp:6556
uint32 GetNativeDisplayId() const
Definition: Unit.h:1603
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:7081
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition: Unit.cpp:4488
virtual void UpdateArmor()=0
bool HealthBelowPct(int32 pct) const
Definition: Unit.h:788
uint64 GetMaxHealth() const
Definition: Unit.h:785
void UpdateCharmAI()
Definition: Unit.cpp:10088
void ClearAllReactives()
Definition: Unit.cpp:10611
void ApplyControlStatesIfNeeded()
Definition: Unit.cpp:11376
void SetRooted(bool apply, bool packetOnly=false)
Definition: Unit.cpp:11423
void AddUnitMovementFlag(uint32 f)
Definition: Unit.h:1704
ThreatManager m_threatManager
Definition: Unit.h:1994
uint32 _oldFactionId
faction before charm
Definition: Unit.h:2013
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:5761
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition: Unit.cpp:12170
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const
Definition: Unit.cpp:9696
bool IsHovering() const
Definition: Unit.h:1146
std::forward_list< Aura * > AuraList
Definition: Unit.h:649
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5108
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition: Unit.cpp:4703
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4629
bool PopAI()
Definition: Unit.cpp:9930
ObjectGuid GetMinionGUID() const
Definition: Unit.h:1186
bool SetCanFly(bool enable)
Definition: Unit.cpp:13220
virtual float GetDamageMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:804
bool SetCollision(bool disable)
Definition: Unit.cpp:13411
bool isPossessed() const
Definition: Unit.h:1228
uint16 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition: Unit.h:927
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:1706
Unit * m_charmed
Definition: Unit.h:1927
virtual void UpdateMaxPower(Powers power)=0
uint64 GetHealth() const
Definition: Unit.h:784
void _AddAura(UnitAura *aura, Unit *caster)
Definition: Unit.cpp:3375
AttackerSet m_attackers
Definition: Unit.h:1879
bool IsSummon() const
Definition: Unit.h:745
bool IsInWater() const
Definition: Unit.cpp:3251
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition: Unit.cpp:11904
uint32 GetFaction() const override
Definition: Unit.h:867
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition: Unit.cpp:13980
void RemoveDynObject(uint32 spellId)
Definition: Unit.cpp:5249
void SendCancelSpellVisual(uint32 id)
Definition: Unit.cpp:12087
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, int32 overEnergize, Powers powerType)
Definition: Unit.cpp:6691
Unit * m_attacking
Definition: Unit.h:1880
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition: Unit.cpp:6052
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition: Unit.cpp:4665
AttackerSet const & getAttackers() const
Definition: Unit.h:720
void RemoveUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:848
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:878
void SetAI(UnitAI *newAI)
Definition: Unit.cpp:9924
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition: Unit.cpp:4547
void SendTeleportPacket(TeleportLocation const &teleportLocation)
Definition: Unit.cpp:12740
bool SetCanTurnWhileFalling(bool enable)
Definition: Unit.cpp:13516
std::multimap< uint32, Aura * > AuraMap
Definition: Unit.h:637
void SendPetTalk(uint32 pettalk)
Definition: Unit.cpp:10397
bool IsVisible() const
Definition: Unit.cpp:8550
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:4743
std::unique_ptr< Vignettes::VignetteData > m_vignette
Definition: Unit.h:1942
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3837
bool isMoving() const
Definition: Unit.h:1776
bool SetWalk(bool enable)
Definition: Unit.cpp:13107
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2790
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster) const
Definition: Unit.cpp:4825
void EngageWithTarget(Unit *who)
Definition: Unit.cpp:8281
void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
Definition: Unit.h:1591
void NearTeleportTo(Position const &pos, bool casting=false)
Definition: Unit.cpp:12726
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition: Unit.cpp:1299
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition: Unit.cpp:2568
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition: Unit.h:694
virtual bool UpdateStats(Stats stat)=0
void RemoveAllDynObjects()
Definition: Unit.cpp:5264
bool HasNpcFlag(NPCFlags flags) const
Definition: Unit.h:991
void GetAllMinionsByEntry(std::list< TempSummon * > &Minions, uint32 entry)
Definition: Unit.cpp:6326
uint32 GetArmor() const
Definition: Unit.h:770
float m_modMeleeHitChance
Definition: Unit.h:1504
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition: Unit.h:1526
void RemoveArenaAuras()
Definition: Unit.cpp:4358
void _RemoveAllAuraStatMods()
Definition: Unit.cpp:4521
ObjectGuid GetCritterGUID() const
Definition: Unit.h:1190
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition: Unit.cpp:3913
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:755
int32 GetTotalAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4998
void SetFullPower(Powers power)
Definition: Unit.h:821
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4170
void SetMovementAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10943
void ClearUpdateMask(bool remove) override
Definition: Unit.cpp:13884
void StopAttackFaction(uint32 faction_id)
Definition: Unit.cpp:12875
bool HasScheduledAIChange() const
Definition: Unit.cpp:9979
void RemoveAreaAurasDueToLeaveWorld()
Definition: Unit.cpp:4278
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition: Unit.cpp:10787
bool CanModifyStats() const
Definition: Unit.h:1538
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition: Unit.cpp:2821
void RemoveCharmedBy(Unit *charmer)
Definition: Unit.cpp:11699
void RemoveMovementForce(ObjectGuid id)
Definition: Unit.cpp:13724
bool IsMounted() const
Definition: Unit.h:907
Trinity::Containers::FlatSet< AuraApplication *, VisibleAuraSlotCompare > m_visibleAurasToUpdate
Definition: Unit.h:1919
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage) const =0
bool IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
Definition: Unit.cpp:9299
void SetMaxHealth(uint64 val)
Definition: Unit.cpp:9758
float GetSpeedRate(UnitMoveType mtype) const
Definition: Unit.h:1679
void SendPetAIReaction(ObjectGuid guid)
Definition: Unit.cpp:10409
std::set< Unit * > AttackerSet
Definition: Unit.h:633
virtual void SetTarget(ObjectGuid const &)=0
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3824
virtual uint32 GetPowerIndex(Powers power) const =0
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition: Unit.cpp:10052
bool IsGuardian() const
Definition: Unit.h:746
void UpdateStatBuffModForClient(Stats stat)
Definition: Unit.cpp:5213
Unit * GetVictim() const
Definition: Unit.h:722
void UpdatePetCombatState()
Definition: Unit.cpp:9050
std::vector< Unit * > UnitVector
Definition: Unit.h:635
uint32 GetExtraUnitMovementFlags() const
Definition: Unit.h:1713
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition: Unit.h:1858
int32 GetPower(Powers power) const
Definition: Unit.cpp:9782
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition: Unit.cpp:7473
uint64 CountPctFromMaxHealth(int32 pct) const
Definition: Unit.h:793
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition: Unit.cpp:9666
bool HasExtraUnitMovementFlag2(uint32 f) const
Definition: Unit.h:1718
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition: Unit.cpp:12847
bool IsUnderWater() const
Definition: Unit.cpp:3256
void SetBattlePetCompanionGUID(ObjectGuid guid)
Definition: Unit.h:1193
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition: Unit.cpp:8729
void AddExtraAttacks(uint32 count)
Definition: Unit.cpp:2325
void RemovePlayerFromVision(Player *player)
Definition: Unit.cpp:6627
void SendFlightSplineSyncUpdate()
Definition: Unit.cpp:632
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition: Unit.cpp:7643
float GetCreateStat(Stats stat) const
Definition: Unit.h:1412
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition: Unit.cpp:13914
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition: Unit.cpp:10276
void UpdateSplinePosition()
Definition: Unit.cpp:608
void SetOwnerGUID(ObjectGuid owner)
Definition: Unit.cpp:6077
DeathState getDeathState() const
Definition: Unit.h:1179
bool SetIgnoreMovementForces(bool ignore)
Definition: Unit.cpp:13752
Unit * GetFirstControlled() const
Definition: Unit.cpp:6505
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:5028
void SetFacingTo(float const ori, bool force=true)
Definition: Unit.cpp:13053
ObjectGuid GetTransGUID() const override
Definition: Unit.cpp:11894
bool m_aiLocked
Definition: Unit.h:2001
void ApplyCastTimePercentMod(float val, bool apply)
Definition: Unit.cpp:10745
int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5118
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition: Unit.cpp:5239
virtual float GetHealthMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:803
bool IsCritter() const
Definition: Unit.h:1020
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1501
uint16 _movementAnimKitId
Definition: Unit.h:2019
bool CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading=false)
Definition: Unit.cpp:11827
bool HasUnitState(const uint32 f) const
Definition: Unit.h:739
bool IsMagnet() const
Definition: Unit.cpp:6479
std::unordered_set< AbstractFollower * > m_followingMe
Definition: Unit.h:2003
virtual void Update(uint32 time) override
Definition: Unit.cpp:423
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11930
void UnsummonAllTotems()
Definition: Unit.cpp:6650
AuraApplication * _CreateAuraApplication(Aura *aura, uint32 effMask)
Definition: Unit.cpp:3414
uint16 _meleeAnimKitId
Definition: Unit.h:2020
void _UnregisterAreaTrigger(AreaTrigger *areaTrigger)
Definition: Unit.cpp:5391
GameObjectList m_gameObj
Definition: Unit.h:1891
int32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 pdamage, DamageEffectType damagetype) const
Definition: Unit.cpp:6900
void RemoveExtraUnitMovementFlag2(uint32 f)
Definition: Unit.h:1717
AuraMap m_ownedAuras
Definition: Unit.h:1900
std::array< float, MAX_STATS > m_createStats
Definition: Unit.h:1875
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition: Unit.cpp:3266
Unit(bool isWorldObject)
Definition: Unit.cpp:308
bool IsInFeralForm() const
Definition: Unit.cpp:9288
DynamicObject * GetDynObject(uint32 spellId) const
Definition: Unit.cpp:5233
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition: Unit.cpp:9710
std::unique_ptr< Movement::MoveSpline > movespline
Definition: Unit.h:1810
bool _playHoverAnim
Definition: Unit.h:2016
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7186
void CalculateHoverHeight()
Definition: Unit.cpp:13832
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition: Unit.h:639
void RemoveUnitMovementFlag(uint32 f)
Definition: Unit.h:1705
static std::vector< AuraEffect * > CopyAuraEffectList(AuraEffectList const &list)
Definition: Unit.cpp:791
void RemoveBindSightAuras()
Definition: Unit.cpp:6637
std::array< float, ADV_FLYING_MAX_SPEED_TYPE > m_advFlyingSpeed
Definition: Unit.h:1922
void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
Definition: Unit.cpp:12095
AuraApplicationMap m_appliedAuras
Definition: Unit.h:1901
CharmInfo * InitCharmInfo()
Definition: Unit.cpp:10132
void RemoveAllAttackers()
Definition: Unit.cpp:5972
void SetClass(uint8 classId)
Definition: Unit.h:761
virtual bool CanSwim() const
Definition: Unit.cpp:12712
virtual float GetNativeObjectScale() const
Definition: Unit.h:1598
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition: Unit.cpp:4889
void RemoveFromWorld() override
Definition: Unit.cpp:9995
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId)
-------—Pet responses methods--------------—
Definition: Unit.cpp:10385
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition: Unit.cpp:2216
bool IsOnOceanFloor() const
Definition: Unit.cpp:3261
void ScheduleAIChange()
Definition: Unit.cpp:9950
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4733
Powers CalculateDisplayPowerType() const
Definition: Unit.cpp:5670
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition: Unit.h:743
std::array< float, MAX_MOVE_TYPE > m_speed_rate
Definition: Unit.h:1921
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition: Unit.cpp:9409
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition: Unit.cpp:3658
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition: Unit.cpp:5508
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition: Unit.cpp:12524
float GetMeleeRange(Unit const *target) const
Definition: Unit.cpp:695
bool isDying() const
Definition: Unit.h:1177
void DoMeleeAttackIfReady()
Definition: Unit.cpp:2130
float GetStat(Stats stat) const
Definition: Unit.h:768
void SendMeleeAttackStop(Unit *victim=nullptr)
Definition: Unit.cpp:2512
void RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition: Unit.cpp:4231
void SendDurabilityLoss(Player *receiver, uint32 percent)
Definition: Unit.cpp:10906
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5058
int32 MeleeDamageBonusDone(Unit *pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, SpellEffectInfo const *spellEffectInfo=nullptr, Mechanics mechanic=MECHANIC_NONE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, Spell *spell=nullptr, AuraEffect const *aurEff=nullptr)
Definition: Unit.cpp:7808
virtual float GetBlockPercent(uint8) const
Definition: Unit.h:983
void RemoveAllAuras()
Definition: Unit.cpp:4311
SpellHistory * GetSpellHistory()
Definition: Unit.h:1488
std::array< float, MAX_ATTACK > m_modAttackSpeedPct
Definition: Unit.h:1510
bool IsBlockCritical() const
Definition: Unit.cpp:2522
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition: Unit.cpp:1629
bool IsControlledByPlayer() const
Definition: Unit.h:1205
Unit * m_charmer
Definition: Unit.h:1926
void SetVisibleAura(AuraApplication *aurApp)
Definition: Unit.cpp:711
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition: Unit.cpp:9099
bool m_canDualWield
Definition: Unit.h:711
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1199
bool HasAuraWithMechanic(uint64 mechanicMask) const
Definition: Unit.cpp:4808
Minion * GetFirstMinion() const
Definition: Unit.cpp:6121
UnitStandStateType GetStandState() const
Definition: Unit.h:895
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition: Unit.cpp:7330
UnitAI * GetScheduledChangeAI()
Definition: Unit.cpp:9971
uint16 _aiAnimKitId
Definition: Unit.h:2018
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition: Unit.cpp:4774
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition: Unit.cpp:753
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition: Unit.cpp:11526
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition: Unit.cpp:8519
void SetPetGUID(ObjectGuid guid)
Definition: Unit.h:1189
bool SetWaterWalking(bool enable)
Definition: Unit.cpp:13263
void TriggerAurasProcOnEvent(AuraApplicationList *myProcAuras, AuraApplicationList *targetProcAuras, Unit *actionTarget, ProcFlagsInit const &typeMaskActor, ProcFlagsInit const &typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:10321
void SetMaxPower(Powers power, int32 val)
Definition: Unit.cpp:9837
std::vector< std::pair< uint32, AuraApplication * > > AuraApplicationProcContainer
Definition: Unit.h:653
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:8938
void SetCreatorGUID(ObjectGuid creator)
Definition: Unit.h:1185
void GetPartyMembers(std::list< Unit * > &units)
Definition: Unit.cpp:11949
void RemoveVehicleKit(bool onRemoveFromWorld=false)
Definition: Unit.cpp:11843
ObjectGuid LastCharmerGUID
Definition: Unit.h:1751
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition: Unit.cpp:12286
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition: Unit.cpp:13856
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2707
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:1647
int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5128
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition: Unit.cpp:9342
CombatManager & GetCombatManager()
Definition: Unit.h:1033
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:842
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition: Unit.cpp:2340
void UpdateMovementForcesModMagnitude()
Definition: Unit.cpp:13783
uint32 GetCreatureTypeMask() const
Definition: Unit.cpp:9245
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition: Unit.cpp:10869
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition: Unit.cpp:4783
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:4765
bool IsFlying() const
Definition: Unit.h:1779
void SetCritterGUID(ObjectGuid guid)
Definition: Unit.h:1191
AuraApplicationMap & GetAppliedAuras()
Definition: Unit.h:1286
void ClearBossEmotes(Optional< uint32 > zoneId={}, Player const *target=nullptr) const
Clears boss emotes frame.
Definition: Unit.cpp:14070
void RemoveMovementImpairingAuras(bool withRoot)
Definition: Unit.cpp:4223
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:697
void SetVignette(uint32 vignetteId)
Definition: Unit.cpp:14197
void InitStatBuffMods()
Definition: Unit.cpp:5138
int32 m_procDeep
Definition: Unit.h:1884
int32 GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5098
void ClearDiminishings()
Definition: Unit.cpp:9221
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition: Unit.cpp:9123
bool IsUninteractible() const
Definition: Unit.h:1047
std::vector< AreaTrigger * > GetAreaTriggers(uint32 spellId) const
Definition: Unit.cpp:5404
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData)
Definition: Unit.cpp:3274
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition: Unit.cpp:5276
std::array< uint32, MAX_ATTACK > m_attackTimer
Definition: Unit.h:1511
bool IsServiceProvider() const
Definition: Unit.cpp:8272
MountCapabilityEntry const * GetMountCapability(uint32 mountType) const
Definition: Unit.cpp:8149
bool IsTotem() const
Definition: Unit.h:749
CombatManager m_combatManager
Definition: Unit.h:1992
void ChangeSeat(int8 seatId, bool next=true)
Definition: Unit.cpp:12571
void SetInFront(WorldObject const *target)
Definition: Unit.cpp:13047
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition: Unit.cpp:9204
AuraStateAurasMap m_auraStateAuras
Definition: Unit.h:1909
int32 GetResistance(SpellSchools school) const
Definition: Unit.h:777
AuraList & GetSingleCastAuras()
Definition: Unit.h:1335
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition: Unit.cpp:8539
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4575
Vehicle * GetVehicleKit() const
Definition: Unit.h:1754
bool CanCastSpellWhileMoving(SpellInfo const *spellInfo) const
Definition: Unit.cpp:3202
void PushAI(UnitAI *newAI)
Definition: Unit.cpp:9919
float m_modSpellHitChance
Definition: Unit.h:1506
void ValidateAttackersAndOwnTarget()
Definition: Unit.cpp:5900
Guardian * GetGuardianPet() const
Definition: Unit.cpp:6137
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition: Unit.cpp:659
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4659
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition: Unit.cpp:13962
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, ProcFlagsInit const &typeMaskActor, ProcFlagsInit const &typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:5476
virtual bool IsEngaged() const
Definition: Unit.h:1029
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const &familyFlag, ObjectGuid casterGUID)
Definition: Unit.cpp:4205
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition: Unit.cpp:3456
void DeMorph()
Definition: Unit.cpp:3307
void RemoveAllMinionsByEntry(uint32 entry)
Definition: Unit.cpp:6336
AuraMap & GetOwnedAuras()
Definition: Unit.h:1276
void UpdateAllDamagePctDoneMods()
Definition: Unit.cpp:9570
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition: Unit.cpp:6990
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition: Unit.cpp:13985
bool IsFalling() const
Definition: Unit.cpp:12707
bool AttackStop()
Definition: Unit.cpp:5872
std::array< float, MAX_STATS > m_floatStatNegBuff
Definition: Unit.h:1877
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition: Unit.cpp:3174
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, SpellInfo const *spellInfo) const override
Definition: Unit.cpp:12181
void RemoveAurasOnEvade()
Definition: Unit.cpp:4372
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, int32 effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications=false)
Definition: Unit.cpp:13923
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition: Unit.cpp:9391
void SetShapeshiftForm(ShapeshiftForm form)
Definition: Unit.cpp:9251
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition: Unit.cpp:2887
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11911
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3897
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.cpp:10975
bool m_cleanupDone
Definition: Unit.h:2009
SharedVisionList m_sharedVision
Definition: Unit.h:1929
void SetMeleeAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10959
EnumFlag< SpellAuraInterruptFlags > m_interruptMask
Definition: Unit.h:1910
std::array< AuraEffectList, TOTAL_AURAS > m_modAuras
Definition: Unit.h:1906
int32 SpellHealingBonusDone(Unit *victim, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, uint32 stack=1, Spell *spell=nullptr, AuraEffect const *aurEff=nullptr) const
Definition: Unit.cpp:7234
ObjectGuid GetTarget() const
Definition: Unit.h:1803
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition: Unit.h:2014
void SetPowerType(Powers power, bool sendUpdate=true, bool onInit=false)
Definition: Unit.cpp:5605
uint8 GetLevel() const
Definition: Unit.h:753
void SetMountDisplayId(uint32 mountDisplayId)
Definition: Unit.h:909
uint8 GetRace() const
Definition: Unit.h:757
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange=false)
Definition: Unit.cpp:4088
virtual void SetDisplayId(uint32 displayId, bool setNative=false)
Definition: Unit.cpp:10532
void TriggerAuraHeartbeat()
Definition: Unit.cpp:517
void RemoveCharmAuras()
Definition: Unit.cpp:6642
bool IsInCombat() const
Definition: Unit.h:1053
bool IsWalking() const
Definition: Unit.h:1145
void SetWildBattlePetLevel(uint32 wildBattlePetLevel)
Definition: Unit.h:1262
bool IsSitState() const
Definition: Unit.cpp:10469
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition: Unit.cpp:3079
GetCastSpellInfoResult GetCastSpellInfo(SpellInfo const *spellInfo) const
Definition: Unit.h:1470
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition: Unit.cpp:12292
void RemoveUnitFlag(UnitFlags flags)
Definition: Unit.h:843
void SetAIAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10927
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition: Unit.cpp:533
uint16 GetVirtualItemAppearanceMod(uint32 slot) const
Definition: Unit.cpp:14004
Unit * GetDemonCreator() const
Definition: Unit.cpp:6098
Player * m_playerMovingMe
Definition: Unit.h:1925
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer, int32 stolenCharges=1)
Definition: Unit.cpp:3958
AreaTrigger * GetAreaTrigger(uint32 spellId) const
Definition: Unit.cpp:5398
uint32 GetDamageImmunityMask() const
Definition: Unit.cpp:7613
Player * GetControllingPlayer() const
Definition: Unit.cpp:6108
float GetWeaponProcChance() const
Definition: Unit.cpp:8046
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition: Unit.cpp:3312
ObjectGuid GetPetGUID() const
Definition: Unit.h:1188
void UpdateStatBuffMod(Stats stat)
Definition: Unit.cpp:5148
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12603
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition: Unit.h:1914
void CombatStopWithPets(bool includingCast=false)
Definition: Unit.cpp:5946
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1456
bool BuildPacket(WorldPacket *packet)
Definition: UpdateData.cpp:40
Unit * GetBase() const
Definition: Vehicle.h:49
Vehicle * RemovePassenger(WorldObject *passenger) override
Removes the passenger from the vehicle.
Definition: Vehicle.cpp:495
uint32 GetCreatureEntry() const
Definition: Vehicle.h:51
void Uninstall()
Removes all passengers and sets status to STATUS_UNINSTALLING. No new passengers can be added to the ...
Definition: Vehicle.cpp:109
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition: Vehicle.cpp:557
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition: Vehicle.h:67
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:314
VehicleSeatAddon const * GetSeatAddonForSeatOfPassenger(Unit const *passenger) const
Gets the vehicle seat addon data for the seat of a passenger.
Definition: Vehicle.cpp:355
Milliseconds GetDespawnDelay()
Definition: Vehicle.cpp:961
void InstallAllAccessories(bool evading)
Definition: Vehicle.cpp:85
bool AddVehiclePassenger(Unit *unit, int8 seatId=-1)
Definition: Vehicle.cpp:424
constexpr uint32 GetMapId() const
Definition: Position.h:215
int8 GetTransSeat() const
Definition: Object.h:897
bool InSamePhase(PhaseShift const &phaseShift) const
Definition: Object.h:665
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition: Object.cpp:1187
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1815
Map * GetMap() const
Definition: Object.h:762
ZLiquidStatus GetLiquidStatus() const
Definition: Object.h:688
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1436
void AddToWorld() override
Definition: Object.cpp:1076
virtual bool IsAlwaysVisibleFor(WorldObject const *seer) const
Definition: Object.h:962
Unit * GetCharmerOrOwner() const
Definition: Object.cpp:2329
void RemoveFromWorld() override
Definition: Object.cpp:1082
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1107
virtual uint8 GetLevelForTarget(WorldObject const *) const
Definition: Object.h:736
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition: Object.cpp:2767
Unit * GetCharmerOrOwnerOrSelf() const
Definition: Object.cpp:2339
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition: Object.cpp:1854
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2993
std::string GetDebugInfo() const override
Definition: Object.cpp:3899
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3105
virtual bool IsAlwaysDetectableFor(WorldObject const *seer) const
Definition: Object.h:965
bool IsHostileTo(WorldObject const *target) const
Definition: Object.cpp:2957
PhaseShift & GetPhaseShift()
Definition: Object.h:661
Unit * GetOwner() const
Definition: Object.cpp:2324
ZoneScript * GetZoneScript() const
Definition: Object.h:768
TransportBase * GetTransport() const
Definition: Object.h:890
void setActive(bool isActiveObject)
Definition: Object.cpp:987
float GetFloorZ() const
Definition: Object.cpp:3869
std::string const & GetName() const
Definition: Object.h:693
virtual void Heartbeat()
Definition: Object.h:967
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1246
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition: Object.cpp:1064
Player * GetSpellModOwner() const
Definition: Object.cpp:2367
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2347
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1212
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition: Object.cpp:968
void AddToNotify(uint16 f)
Definition: Object.h:872
EventProcessor m_Events
Definition: Object.h:917
float GetVisibilityRange() const
Definition: Object.cpp:1512
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition: Object.cpp:3400
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition: Object.cpp:2718
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1143
uint32 GetAreaId() const
Definition: Object.h:684
uint32 GetZoneId() const
Definition: Object.h:683
MovementInfo m_movementInfo
Definition: Object.h:901
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition: Object.h:757
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2962
bool IsInMap(WorldObject const *obj) const
Definition: Object.cpp:1180
virtual void Update(uint32 diff)
Definition: Object.cpp:956
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition: Object.cpp:2776
virtual void UpdateObjectVisibility(bool forced=true)
Definition: Object.cpp:3764
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition: Object.cpp:1046
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: ChatPackets.h:235
WorldPacket const * Write() override
std::vector< int32 > SpellVisualKitIDs
Definition: ChatPackets.h:198
WorldPacket const * Write() override
Optional< Spells::ContentTuningParams > ContentTuning
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< PowerUpdatePower > Powers
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
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::XY > Direction
WorldPacket const * Write() override
WorldPacket const * Write() override
uint32 SequenceIndex
Unit movement packet index, incremented each time.
WorldPacket const * Write() override
uint32 SequenceIndex
Unit movement packet index, incremented each time.
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > Pos
Optional< ObjectGuid > TransportGUID
WorldPacket const * Write() override
::MovementForces::Container const * MovementForces
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: PetPackets.cpp:190
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > TargetPosition
Definition: SpellPackets.h:751
WorldPacket const * Write() override
WorldPacket const * Write() override
LocaleConstant GetSessionDbLocaleIndex() const
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
OpcodeServer
Definition: Opcodes.h:956
@ SMSG_MOVE_SPLINE_SET_PITCH_RATE
Definition: Opcodes.h:1687
@ SMSG_MOVE_SET_ADV_FLYING_LAUNCH_SPEED_COEFFICIENT
Definition: Opcodes.h:1642
@ SMSG_MOVE_UNSET_CANT_SWIM
Definition: Opcodes.h:1704
@ SMSG_MOVE_SPLINE_SET_SWIM_SPEED
Definition: Opcodes.h:1692
@ SMSG_MOVE_SET_FLIGHT_SPEED
Definition: Opcodes.h:1659
@ SMSG_MOVE_SPLINE_SET_FLYING
Definition: Opcodes.h:1683
@ SMSG_MOVE_SET_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1658
@ SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION
Definition: Opcodes.h:1648
@ SMSG_MOVE_DISABLE_COLLISION
Definition: Opcodes.h:1620
@ SMSG_MOVE_UPDATE_PITCH_RATE
Definition: Opcodes.h:1720
@ SMSG_MOVE_SPLINE_SET_WALK_SPEED
Definition: Opcodes.h:1695
@ SMSG_MOVE_ENABLE_DOUBLE_JUMP
Definition: Opcodes.h:1627
@ SMSG_MOVE_ROOT
Definition: Opcodes.h:1635
@ SMSG_MOVE_SPLINE_SET_RUN_MODE
Definition: Opcodes.h:1689
@ SMSG_MOVE_DISABLE_GRAVITY
Definition: Opcodes.h:1623
@ SMSG_MOVE_SPLINE_SET_SWIM_BACK_SPEED
Definition: Opcodes.h:1691
@ SMSG_MOVE_SPLINE_DISABLE_COLLISION
Definition: Opcodes.h:1675
@ SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition: Opcodes.h:1631
@ SMSG_MOVE_UNROOT
Definition: Opcodes.h:1703
@ SMSG_MOVE_SPLINE_UNROOT
Definition: Opcodes.h:1699
@ SMSG_MOVE_SET_RUN_BACK_SPEED
Definition: Opcodes.h:1666
@ SMSG_MOVE_SPLINE_SET_HOVER
Definition: Opcodes.h:1684
@ SMSG_MOVE_SPLINE_SET_WATER_WALK
Definition: Opcodes.h:1696
@ SMSG_MOVE_SPLINE_SET_NORMAL_FALL
Definition: Opcodes.h:1686
@ SMSG_MOVE_ENABLE_INERTIA
Definition: Opcodes.h:1630
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_DOWN
Definition: Opcodes.h:1646
@ SMSG_MOVE_SPLINE_SET_TURN_RATE
Definition: Opcodes.h:1693
@ SMSG_MOVE_SET_NORMAL_FALL
Definition: Opcodes.h:1664
@ SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE
Definition: Opcodes.h:1639
@ SMSG_MOVE_SET_ADV_FLYING_LIFT_COEFFICIENT
Definition: Opcodes.h:1643
@ SMSG_MOVE_SPLINE_UNSET_HOVER
Definition: Opcodes.h:1701
@ SMSG_MOVE_UPDATE_FLIGHT_SPEED
Definition: Opcodes.h:1717
@ SMSG_MOVE_SET_PITCH_RATE
Definition: Opcodes.h:1665
@ SMSG_MOVE_SPLINE_SET_LAND_WALK
Definition: Opcodes.h:1685
@ SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1716
@ SMSG_MOVE_UPDATE_WALK_SPEED
Definition: Opcodes.h:1729
@ SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING
Definition: Opcodes.h:1654
@ SMSG_MOVE_SPLINE_DISABLE_GRAVITY
Definition: Opcodes.h:1676
@ SMSG_MOVE_ENABLE_COLLISION
Definition: Opcodes.h:1626
@ SMSG_MOVE_SET_IGNORE_MOVEMENT_FORCES
Definition: Opcodes.h:1661
@ SMSG_MOVE_DISABLE_FULL_SPEED_TURNING
Definition: Opcodes.h:1622
@ SMSG_MOVE_UNSET_IGNORE_MOVEMENT_FORCES
Definition: Opcodes.h:1710
@ SMSG_MOVE_UPDATE_SWIM_SPEED
Definition: Opcodes.h:1726
@ SMSG_MOVE_ENABLE_GRAVITY
Definition: Opcodes.h:1629
@ SMSG_MOVE_UPDATE_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition: Opcodes.h:1719
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP
Definition: Opcodes.h:1647
@ SMSG_MOVE_SET_ADV_FLYING_OVER_MAX_DECELERATION
Definition: Opcodes.h:1645
@ SMSG_MOVE_SET_ADV_FLYING_MAX_VEL
Definition: Opcodes.h:1644
@ SMSG_MOVE_UNSET_HOVERING
Definition: Opcodes.h:1709
@ SMSG_MOVE_UNSET_CAN_ADV_FLY
Definition: Opcodes.h:1705
@ SMSG_MOVE_UPDATE_TURN_RATE
Definition: Opcodes.h:1728
@ SMSG_MOVE_SPLINE_SET_RUN_BACK_SPEED
Definition: Opcodes.h:1688
@ SMSG_MOVE_SET_TURN_RATE
Definition: Opcodes.h:1670
@ SMSG_MOVE_SET_WATER_WALK
Definition: Opcodes.h:1673
@ SMSG_MOVE_SPLINE_ROOT
Definition: Opcodes.h:1679
@ SMSG_MOVE_SET_CANT_SWIM
Definition: Opcodes.h:1650
@ SMSG_MOVE_SET_SWIM_SPEED
Definition: Opcodes.h:1669
@ SMSG_MOVE_UPDATE_RUN_SPEED
Definition: Opcodes.h:1724
@ SMSG_MOVE_SET_WALK_SPEED
Definition: Opcodes.h:1672
@ SMSG_MOVE_SET_HOVERING
Definition: Opcodes.h:1660
@ SMSG_MOVE_SET_ADV_FLYING_ADD_IMPULSE_MAX_SPEED
Definition: Opcodes.h:1637
@ SMSG_MOVE_ENABLE_FULL_SPEED_TURNING
Definition: Opcodes.h:1628
@ SMSG_MOVE_SET_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition: Opcodes.h:1663
@ SMSG_MOVE_SET_ADV_FLYING_GLIDE_START_MIN_HEIGHT
Definition: Opcodes.h:1641
@ SMSG_MOVE_SPLINE_ENABLE_GRAVITY
Definition: Opcodes.h:1678
@ SMSG_MOVE_SET_CAN_FLY
Definition: Opcodes.h:1653
@ SMSG_MOVE_SPLINE_SET_RUN_SPEED
Definition: Opcodes.h:1690
@ SMSG_MOVE_DISABLE_INERTIA
Definition: Opcodes.h:1624
@ SMSG_MOVE_SET_CAN_ADV_FLY
Definition: Opcodes.h:1651
@ SMSG_MOVE_SPLINE_SET_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1681
@ SMSG_MOVE_UPDATE_SWIM_BACK_SPEED
Definition: Opcodes.h:1725
@ SMSG_MOVE_DISABLE_DOUBLE_JUMP
Definition: Opcodes.h:1621
@ SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD
Definition: Opcodes.h:1649
@ SMSG_MOVE_UNSET_CAN_FLY
Definition: Opcodes.h:1707
@ SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD
Definition: Opcodes.h:1640
@ SMSG_MOVE_SPLINE_UNSET_FLYING
Definition: Opcodes.h:1700
@ SMSG_MOVE_SPLINE_SET_FLIGHT_SPEED
Definition: Opcodes.h:1682
@ SMSG_MOVE_SPLINE_STOP_SWIM
Definition: Opcodes.h:1698
@ SMSG_MOVE_SPLINE_START_SWIM
Definition: Opcodes.h:1697
@ SMSG_MOVE_UPDATE_RUN_BACK_SPEED
Definition: Opcodes.h:1723
@ SMSG_MOVE_SET_SWIM_BACK_SPEED
Definition: Opcodes.h:1668
@ SMSG_MOVE_UNSET_CAN_TURN_WHILE_FALLING
Definition: Opcodes.h:1708
@ SMSG_MOVE_SET_RUN_SPEED
Definition: Opcodes.h:1667
@ SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition: Opcodes.h:1625
@ SMSG_MOVE_SPLINE_ENABLE_COLLISION
Definition: Opcodes.h:1677
@ SMSG_MOVE_SET_ADV_FLYING_AIR_FRICTION
Definition: Opcodes.h:1638
@ SMSG_MOVE_SET_LAND_WALK
Definition: Opcodes.h:1662
@ SMSG_MOVE_SPLINE_SET_FEATHER_FALL
Definition: Opcodes.h:1680
@ SMSG_MOVE_SPLINE_SET_WALK_MODE
Definition: Opcodes.h:1694
@ SMSG_MOVE_SET_FEATHER_FALL
Definition: Opcodes.h:1657
#define sWorld
Definition: World.h:927
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition: World.h:314
@ CONFIG_DURABILITY_LOSS_IN_PVP
Definition: World.h:103
@ RATE_POWER_RAGE_INCOME
Definition: World.h:454
@ RATE_DURABILITY_LOSS_DAMAGE
Definition: World.h:525
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition: World.h:524
@ CONFIG_LISTEN_RANGE_YELL
Definition: World.h:211
@ CONFIG_LISTEN_RANGE_SAY
Definition: World.h:209
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition: World.h:210
void apply(T *val)
Definition: ByteConverter.h:41
TimePoint Now()
Current chrono steady_clock time point.
Definition: GameTime.cpp:59
time_t GetGameTime()
Definition: GameTime.cpp:44
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
ItemContext GetContextForPlayer(MapDifficultyEntry const *mapDifficulty, Player const *player)
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API HashMapHolder< Player >::MapType const & GetPlayers()
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Pet * GetPet(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
std::list< T, Alloc >::iterator RemoveUnique(std::list< T, Alloc > &list, std::type_identity_t< T > const &value)
Definition: ListUtils.h:27
auto MapEqualRange(M &map, typename M::key_type const &key)
Definition: IteratorPair.h:60
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition: Containers.h:110
bool IsValidMapCoord(float c)
Definition: GridDefines.h:227
UpdateFieldFlag
Definition: UpdateField.h:34
std::unique_ptr< VignetteData > Create(VignetteEntry const *vignetteData, WorldObject const *owner)
Definition: Vignette.cpp:81
void Update(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:101
void Remove(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:113
STL namespace.
ObjectGuid CasterGUID
int32 const * BaseAmount
ObjectGuid CastItemGUID
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCaster(Unit *caster)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
uint32 GetAuraEffectMask() const
SpellInfo const * GetSpellInfo() const
WeaponAttackType AttackType
Definition: Unit.h:543
ProcFlagsInit ProcAttacker
Definition: Unit.h:544
uint32 DamageSchoolMask
Definition: Unit.h:532
Unit * Target
Definition: Unit.h:531
uint32 TargetState
Definition: Unit.h:539
MeleeHitOutcome HitOutCome
Definition: Unit.h:547
Unit * Attacker
Definition: Unit.h:530
uint32 Damage
Definition: Unit.h:533
uint32 RageGained
Definition: Unit.h:540
uint32 Blocked
Definition: Unit.h:537
uint32 Resist
Definition: Unit.h:536
uint32 CleanDamage
Definition: Unit.h:546
uint32 HitInfo
Definition: Unit.h:538
uint32 Absorb
Definition: Unit.h:535
uint32 OriginalDamage
Definition: Unit.h:534
ProcFlagsInit ProcVictim
Definition: Unit.h:545
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
Definition: SpellDefines.h:519
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
void SaveStayPosition()
Definition: Unit.cpp:12996
float _stayY
Definition: CharmInfo.h:153
void SetIsCommandFollow(bool val)
Definition: Unit.cpp:12986
bool IsCommandAttack()
Definition: Unit.cpp:12981
bool _isAtStay
Definition: CharmInfo.h:149
void InitPossessCreateSpells()
Definition: CharmInfo.cpp:74
void SetIsAtStay(bool val)
Definition: Unit.cpp:13017
bool IsFollowing()
Definition: Unit.cpp:13032
float _stayX
Definition: CharmInfo.h:152
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition: CharmInfo.cpp:238
float _stayZ
Definition: CharmInfo.h:154
bool IsReturning()
Definition: Unit.cpp:13042
void SetIsFollowing(bool val)
Definition: Unit.cpp:13027
bool _isCommandFollow
Definition: CharmInfo.h:148
void SetIsReturning(bool val)
Definition: Unit.cpp:13037
void InitCharmCreateSpells()
Definition: CharmInfo.cpp:113
bool IsAtStay()
Definition: Unit.cpp:13022
bool _isFollowing
Definition: CharmInfo.h:150
bool _isCommandAttack
Definition: CharmInfo.h:147
void GetStayPosition(float &x, float &y, float &z)
Definition: Unit.cpp:13010
bool IsCommandFollow()
Definition: Unit.cpp:12991
void SetIsCommandAttack(bool val)
Definition: Unit.cpp:12976
bool _isReturning
Definition: CharmInfo.h:151
Unit * _unit
Definition: CharmInfo.h:138
uint8 CreatureType
Definition: DB2Structure.h:857
EnumFlag< ChrRacesFlag > GetFlags() const
Definition: DB2Structure.h:874
uint32 absorbed_damage
Definition: Unit.h:408
WeaponAttackType attackType
Definition: Unit.h:411
bool MovementUpdate
Definition: Object.h:88
bool Vehicle
Definition: Object.h:93
EnumFlag< CreatureModelDataFlags > GetFlags() const
uint32 CreatureDisplayID
Definition: CreatureData.h:441
DeclinedName()=default
uint32 hitCount
Definition: Unit.h:378
uint32 hitTime
Definition: Unit.h:377
uint16 stack
Definition: Unit.h:376
InventoryType GetInventoryType() const
Definition: ItemTemplate.h:827
uint32 GetSubClass() const
Definition: ItemTemplate.h:819
uint32 GetDelay() const
Definition: ItemTemplate.h:845
Definition: Loot.h:286
void NotifyLootList(Map const *map) const
Definition: Loot.cpp:736
bool isLooted() const
Definition: Loot.h:312
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition: Loot.cpp:845
void SetDungeonEncounterId(uint32 dungeonEncounterId)
Definition: Loot.h:310
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT, ItemContext context=ItemContext::NONE)
Definition: Loot.cpp:859
int16 CosmeticParentMapID
int16 ParentMapID
MovementForceType Type
Definition: MovementInfo.h:164
uint32 TransportID
Definition: MovementInfo.h:162
TaggedPosition< Position::XYZ > Origin
Definition: MovementInfo.h:160
ObjectGuid ID
Definition: MovementInfo.h:159
TaggedPosition< Position::XYZ > Direction
Definition: MovementInfo.h:161
ObjectGuid guid
Definition: MovementInfo.h:30
void SetFallTime(uint32 fallTime)
Definition: MovementInfo.h:136
void RemoveMovementFlag(uint32 flag)
Definition: MovementInfo.h:120
struct MovementInfo::TransportInfo transport
bool HasMovementFlag(uint32 flag) const
Definition: MovementInfo.h:121
Position pos
Definition: MovementInfo.h:34
Optional< LiquidData > liquidInfo
Definition: MapDefines.h:165
void Reset()
Definition: Unit.h:616
bool Relocated
Definition: Unit.h:622
constexpr void SetOrientation(float orientation)
Definition: Position.h:81
constexpr float GetPositionX() const
Definition: Position.h:86
constexpr Position()
Definition: Position.h:30
float m_positionZ
Definition: Position.h:65
constexpr float GetPositionY() const
Definition: Position.h:87
float GetRelativeAngle(float x, float y) const
Definition: Position.h:146
std::string ToString() const
Definition: Position.cpp:199
float m_positionX
Definition: Position.h:63
float m_positionY
Definition: Position.h:64
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition: Position.cpp:170
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:135
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:91
constexpr void Relocate(float x, float y)
Definition: Position.h:73
constexpr Position GetPosition() const
Definition: Position.h:94
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition: Position.h:154
void RelocateOffset(Position const &offset)
Definition: Position.cpp:34
constexpr float GetOrientation() const
Definition: Position.h:89
constexpr float GetPositionZ() const
Definition: Position.h:88
EnumFlag< PowerTypeFlags > GetFlags() const
uint8 castFlags
Definition: ObjectMgr.h:441
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, SpellInfo const *_spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId=ObjectGuid::Empty)
Definition: Unit.cpp:302
ObjectGuid castId
Definition: Unit.h:557
Unit * target
Definition: Unit.h:555
uint32 HitInfo
Definition: Unit.h:567
uint32 damage
Definition: Unit.h:560
uint32 absorb
Definition: Unit.h:563
uint32 preHitHealth
Definition: Unit.h:571
SpellCastVisual SpellVisual
Definition: Unit.h:559
Unit * attacker
Definition: Unit.h:556
uint32 schoolMask
Definition: Unit.h:562
SpellInfo const * Spell
Definition: Unit.h:558
bool periodicLog
Definition: Unit.h:565
uint32 cleanDamage
Definition: Unit.h:569
uint32 originalDamage
Definition: Unit.h:561
uint32 resist
Definition: Unit.h:564
uint32 blocked
Definition: Unit.h:566
AuraEffect const * auraEff
Definition: Unit.h:579
EnumFlag< SpellShapeshiftFormFlags > GetFlags() const
EnumFlag< SummonPropertiesFlags > GetFlags() const
WorldLocation Location
Definition: Player.h:1164
Optional< ObjectGuid > TransportGuid
Definition: Player.h:1165
UpdateFieldArray< std::string, 5, 0, 1 > Name
Definition: UpdateFields.h:503
UpdateField< float, 64, 77 > ModRangedHaste
Definition: UpdateFields.h:350
UpdateField< uint8, 64, 65 > StandState
Definition: UpdateFields.h:338
UpdateField< uint32, 32, 49 > AuraState
Definition: UpdateFields.h:322
UpdateField< uint8, 64, 87 > ShapeshiftForm
Definition: UpdateFields.h:361
UpdateFieldArray< int32, 4, 183, 192 > StatNegBuff
Definition: UpdateFields.h:416
UpdateFieldArray< int32, 4, 183, 188 > StatPosBuff
Definition: UpdateFields.h:415
UpdateField< float, 64, 73 > ModCastingSpeed
Definition: UpdateFields.h:346
UpdateFieldArray< int32, 10, 135, 136 > Power
Definition: UpdateFields.h:408
UpdateField< int32, 32, 37 > Level
Definition: UpdateFields.h:305
UpdateField< uint8, 32, 33 > DisplayPower
Definition: UpdateFields.h:301
UpdateField< int64, 32, 35 > Health
Definition: UpdateFields.h:303
UpdateField< float, 32, 57 > NativeXDisplayScale
Definition: UpdateFields.h:331
UpdateField< int32, 96, 124 > FlightCapabilityID
Definition: UpdateFields.h:398
UpdateFieldArray< UF::VisibleItem, 3, 176, 177 > VirtualItems
Definition: UpdateFields.h:412
UpdateField< int64, 32, 36 > MaxHealth
Definition: UpdateFields.h:304
UpdateField< float, 64, 75 > ModSpellHaste
Definition: UpdateFields.h:348
UpdateField< ObjectGuid, 0, 18 > SummonedBy
Definition: UpdateFields.h:287
UpdateField< uint32, 32, 50 > RangedAttackRoundBaseTime
Definition: UpdateFields.h:324
UpdateField< uint8, 64, 84 > SheatheState
Definition: UpdateFields.h:357
UpdateField< ObjectGuid, 0, 17 > CharmedBy
Definition: UpdateFields.h:286
UpdateFieldArray< int32, 10, 135, 146 > MaxPower
Definition: UpdateFields.h:409
UpdateField< float, 64, 78 > ModHasteRegen
Definition: UpdateFields.h:351
UpdateField< int32, 32, 56 > NativeDisplayID
Definition: UpdateFields.h:330
UpdateField< uint32, 0, 8 > NpcFlags2
Definition: UpdateFields.h:273
UpdateField< float, 64, 76 > ModHaste
Definition: UpdateFields.h:349
UpdateField< int32, 0, 6 > DisplayID
Definition: UpdateFields.h:269
UpdateField< uint32, 128, 131 > CurrentAreaID
Definition: UpdateFields.h:404
UpdateField< float, 32, 53 > DisplayScale
Definition: UpdateFields.h:327
UpdateField< uint8, 64, 68 > AnimTier
Definition: UpdateFields.h:341
UpdateField< ObjectGuid, 0, 14 > Charm
Definition: UpdateFields.h:283
UpdateField< uint32, 0, 7 > NpcFlags
Definition: UpdateFields.h:271
UpdateFieldArray< uint32, 2, 180, 181 > AttackRoundBaseTime
Definition: UpdateFields.h:413
UpdateField< uint16, 0, 4 > ItemAppearanceModID
Definition: UpdateFields.h:242
UpdateField< uint16, 0, 5 > ItemVisual
Definition: UpdateFields.h:243
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:239
std::array< uint32, 5 > VisitedSpells
Definition: Unit.h:1462
bool AddSpell(uint32 spellId)
Definition: Unit.cpp:14086
bool operator()(AuraApplication *left, AuraApplication *right) const
Definition: Unit.cpp:14165
VehicleExitParameters ExitParameter
void Add(EntityFragment fragment, bool update)