TrinityCore
Loading...
Searching...
No Matches
Unit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Unit.h"
19#include "AbstractFollower.h"
20#include "Battlefield.h"
21#include "BattlefieldMgr.h"
22#include "Battleground.h"
23#include "BattlegroundPackets.h"
24#include "BattlegroundScore.h"
25#include "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 "MapUtils.h"
57#include "MiscPackets.h"
58#include "MotionMaster.h"
59#include "MovementGenerator.h"
60#include "MovementPackets.h"
61#include "MoveSpline.h"
62#include "MoveSplineInit.h"
63#include "ObjectAccessor.h"
64#include "ObjectMgr.h"
65#include "Opcodes.h"
66#include "OutdoorPvP.h"
67#include "PartyPackets.h"
68#include "Pet.h"
69#include "PetPackets.h"
70#include "PhasingHandler.h"
71#include "Player.h"
72#include "PlayerAI.h"
73#include "QuestDef.h"
74#include "Spell.h"
75#include "ScheduledChangeAI.h"
76#include "SpellAuraEffects.h"
77#include "SpellAuras.h"
78#include "SpellHistory.h"
79#include "SpellInfo.h"
80#include "SpellMgr.h"
81#include "SpellPackets.h"
82#include "StringConvert.h"
83#include "TemporarySummon.h"
84#include "Totem.h"
85#include "Transport.h"
86#include "Util.h"
87#include "Vehicle.h"
88#include "VehiclePackets.h"
89#include "Vignette.h"
90#include "VignettePackets.h"
91#include "World.h"
92#include "WorldPacket.h"
93#include "WorldSession.h"
94#include <queue>
95#include <sstream>
96#include <cmath>
97
99{
100 2.5f, // MOVE_WALK
101 7.0f, // MOVE_RUN
102 4.5f, // MOVE_RUN_BACK
103 4.722222f, // MOVE_SWIM
104 2.5f, // MOVE_SWIM_BACK
105 3.141594f, // MOVE_TURN_RATE
106 7.0f, // MOVE_FLIGHT
107 4.5f, // MOVE_FLIGHT_BACK
108 3.14f // MOVE_PITCH_RATE
109};
110
112{
113 2.5f, // MOVE_WALK
114 7.0f, // MOVE_RUN
115 4.5f, // MOVE_RUN_BACK
116 4.722222f, // MOVE_SWIM
117 2.5f, // MOVE_SWIM_BACK
118 3.141594f, // MOVE_TURN_RATE
119 7.0f, // MOVE_FLIGHT
120 4.5f, // MOVE_FLIGHT_BACK
121 3.14f // MOVE_PITCH_RATE
122};
123
124DispelableAura::DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
125 _aura(aura), _chance(dispelChance), _charges(dispelCharges)
126{
127}
128
130
132{
133 return roll_chance(_chance);
134}
135
136DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
137 : m_attacker(attacker), m_victim(victim), m_damage(damage), m_originalDamage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
138 m_absorb(0), m_resist(0), m_block(0), m_hitMask(PROC_HIT_NONE)
139{
140}
141
143 : m_attacker(dmgInfo.Attacker), m_victim(dmgInfo.Target), m_damage(dmgInfo.Damage), m_originalDamage(dmgInfo.Damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.DamageSchoolMask)),
144 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)
145{
146 switch (dmgInfo.TargetState)
147 {
150 break;
153 break;
154 }
155
158
159 if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
161
162 if (m_block)
164
165 bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
167 switch (dmgInfo.HitOutCome)
168 {
169 case MELEE_HIT_MISS:
171 break;
172 case MELEE_HIT_DODGE:
174 break;
175 case MELEE_HIT_PARRY:
177 break;
178 case MELEE_HIT_EVADE:
180 break;
181 case MELEE_HIT_BLOCK:
184 case MELEE_HIT_NORMAL:
185 if (!damageNullified)
187 break;
188 case MELEE_HIT_CRIT:
189 if (!damageNullified)
191 break;
192 }
193}
194
195DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, ProcFlagsHit hitMask)
196 : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_originalDamage(spellNonMeleeDamage.originalDamage),
197 m_spellInfo(spellNonMeleeDamage.Spell), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
198 m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
199{
200 if (spellNonMeleeDamage.blocked)
202 if (spellNonMeleeDamage.absorb)
204}
205
207{
208 amount = std::max(amount, -static_cast<int32>(GetDamage()));
209 m_damage += amount;
210}
211
213{
214 amount = std::min(amount, GetDamage());
215 m_absorb += amount;
216 m_damage -= amount;
218}
219
221{
222 amount = std::min(amount, GetDamage());
223 m_resist += amount;
224 m_damage -= amount;
225 if (!m_damage)
226 {
229 }
230}
231
233{
234 amount = std::min(amount, GetDamage());
235 m_block += amount;
236 m_damage -= amount;
238 if (!m_damage)
239 {
242 }
243}
244
246{
247 return m_hitMask;
248}
249
250HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
251 : _healer(healer), _target(target), _heal(heal), _originalHeal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
252{
253}
254
256{
257 amount = std::min(amount, GetHeal());
258 _absorb += amount;
259 _heal -= amount;
260 amount = std::min(amount, GetEffectiveHeal());
261 _effectiveHeal -= amount;
263}
264
266{
267 return _hitMask;
268}
269
270ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
271 ProcFlagsInit const& typeMask, ProcFlagsSpellType spellTypeMask,
272 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
273 Spell* spell, DamageInfo* damageInfo,
274 HealInfo* healInfo) :
275 _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget),
276 _typeMask(typeMask), _spellTypeMask(spellTypeMask),
277 _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell),
278 _damageInfo(damageInfo), _healInfo(healInfo)
279{ }
280
282{
283 if (_spell)
284 return _spell->GetSpellInfo();
285 if (_damageInfo)
286 return _damageInfo->GetSpellInfo();
287 if (_healInfo)
288 return _healInfo->GetSpellInfo();
289 return nullptr;
290}
291
293{
294 if (_spell)
295 return _spell->GetSpellInfo()->GetSchoolMask();
296 if (_damageInfo)
297 return _damageInfo->GetSchoolMask();
298 if (_healInfo)
299 return _healInfo->GetSchoolMask();
301}
302
303SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId)
304 : target(_target), attacker(_attacker), castId(_castId), Spell(_spellInfo), SpellVisual(spellVisual), damage(0), originalDamage(0),
305 schoolMask(_schoolMask), absorb(0), resist(0), periodicLog(false), blocked(0), reflectingSpellId(0), HitInfo(0), cleanDamage(0), fullBlock(false), preHitHealth(_target->GetHealth())
306{
307}
308
309Unit::Unit(bool isWorldObject) :
310 WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(std::make_unique<Movement::MoveSpline>()),
311 m_ControlledByPlayer(false), m_procDeep(0), m_procChainLength(0), m_transformSpell(0),
312 m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
313 m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
314 i_motionMaster(std::make_unique<MotionMaster>(this)), m_regenTimer(0), m_vehicle(nullptr),
315 m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
316 m_threatManager(this), m_aiLocked(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
317 _spellHistory(std::make_unique<SpellHistory>(this))
318{
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
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);
585 return true;
586
587 if (SpellCategoryEntry const* category = sSpellCategoryStore.LookupEntry(spellInfo->CategoryId))
588 if (category->GetFlags().HasFlag(SpellCategoryFlags::ResetCooldownUponEndingEncounter))
589 return true;
590
591 return false;
592 }, true);
593}
594
596{
597 if (movespline->Finalized())
598 return;
599
600 movespline->updateState(t_diff);
601 bool arrived = movespline->Finalized();
602
603 if (arrived)
604 {
606
607 if (Optional<AnimTier> animTier = movespline->GetAnimation())
608 SetAnimTier(*animTier);
609 }
610
612}
613
615{
616 Movement::Location loc = movespline->ComputePosition();
617
618 if (movespline->onTransport)
619 {
621 pos.m_positionX = loc.x;
622 pos.m_positionY = loc.y;
623 pos.m_positionZ = loc.z;
625
626 if (TransportBase* transport = GetDirectTransport())
627 transport->GetPositionWithOffset(pos).GetPosition(loc.x, loc.y, loc.z, loc.orientation);
628 else
629 return;
630 }
631
634
635 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
636}
637
639{
640 if (!movespline->isCyclic() || movespline->Finalized())
641 return;
642
644 flightSplineSync.Guid = GetGUID();
645 flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
646 SendMessageToSet(flightSplineSync.Write(), true);
647}
648
650{
651 // TODO: Check if orientation transport offset changed instead of only global orientation
654
657}
658
664
669
670bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
671{
672 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
673 return false;
674
675 float dx = GetPositionX() - obj->GetPositionX();
676 float dy = GetPositionY() - obj->GetPositionY();
677 float dz = GetPositionZ() - obj->GetPositionZ();
678 float distsq = dx * dx + dy * dy + dz * dz;
679
680 float sizefactor = GetCombatReach() + obj->GetCombatReach();
681 float maxdist = dist2compare + sizefactor;
682
683 return distsq < maxdist * maxdist;
684}
685
686bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
687{
688 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
689 return false;
690
691 float dx = pos.GetPositionX() - obj->GetPositionX();
692 float dy = pos.GetPositionY() - obj->GetPositionY();
693 float dz = pos.GetPositionZ() - obj->GetPositionZ();
694 float distsq = dx*dx + dy*dy + dz*dz;
695
697
698 return distsq <= maxdist * maxdist;
699}
700
701float Unit::GetMeleeRange(Unit const* target) const
702{
703 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
704 return std::max(range, NOMINAL_MELEE_RANGE);
705}
706
707bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
708{
709 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
710 return false;
711
712 float objBoundaryRadius = std::max(obj->GetBoundingRadius(), MIN_MELEE_REACH);
713
714 return IsInDist(obj, objBoundaryRadius);
715}
716
718{
719 m_visibleAuras.insert(aurApp);
720 m_visibleAurasToUpdate.insert(aurApp);
722}
723
725{
726 m_visibleAuras.erase(aurApp);
727 m_visibleAurasToUpdate.erase(aurApp);
729}
730
732{
733 m_visibleAurasToUpdate.insert(aurApp);
734}
735
740
742{
745 for (AuraApplication const* aurApp : m_interruptableAuras)
746 {
747 m_interruptMask |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags;
748 m_interruptMask2 |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags2;
749 }
750
752 {
753 if (spell->getState() == SPELL_STATE_CHANNELING)
754 {
755 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
756 m_interruptMask2 |= spell->m_spellInfo->ChannelInterruptFlags2;
757 }
758 }
759}
760
761bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
762{
763 for (AuraEffect const* aura : GetAuraEffectsByType(auraType))
764 if (aura->GetSpellInfo()->SpellFamilyName == familyName && aura->GetSpellInfo()->SpellFamilyFlags & familyFlags)
765 return true;
766 return false;
767}
768
770{
771 for (AuraEffect const* aura : GetAuraEffectsByType(type))
772 if ((!excludeAura || excludeAura != aura->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
773 aura->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask))
774 return true;
775 return false;
776}
777
778bool Unit::HasBreakableByDamageCrowdControlAura(Unit const* excludeCasterChannel) const
779{
781 return false;
782
783 uint32 excludeAura = 0;
784 if (excludeCasterChannel)
785 if (Spell const* currentChanneledSpell = excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
786 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
787
788 // This function is named after spell attribute it is meant for - SPELL_ATTR6_DO_NOT_CHAIN_TO_CROWD_CONTROLLED_TARGETS
789 // Not checking aura type is not a mistake here
790 for (AuraApplication const* aurApp : m_interruptableAuras)
791 if (!aurApp->IsPositive()
792 && (!excludeAura || excludeAura != aurApp->GetBase()->GetId())
793 && aurApp->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask))
794 return true;
795
796 return false;
797}
798
799/*static*/ void Unit::DealDamageMods(Unit const* attacker, Unit const* victim, uint32& damage, uint32* absorb)
800{
801 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
802 {
803 if (absorb)
804 *absorb += damage;
805 damage = 0;
806 return;
807 }
808
809 if (attacker)
810 damage *= attacker->GetDamageMultiplierForTarget(victim);
811}
812
814{
815 AuraEffectVector effects;
816 std::copy(list.begin(), list.end(), std::back_inserter(effects));
817 return effects;
818}
819
820/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
821{
822 uint32 damageDone = damage;
823 uint32 damageTaken = damage;
824 if (attacker)
825 damageTaken = damage / victim->GetHealthMultiplierForTarget(attacker);
826
827 // call script hooks
828 {
829 uint32 tmpDamage = damageTaken;
830
831 // sparring
832 if (Creature* victimCreature = victim->ToCreature())
833 tmpDamage = victimCreature->CalculateDamageForSparring(attacker, tmpDamage);
834
835 if (UnitAI* victimAI = victim->GetAI())
836 victimAI->DamageTaken(attacker, tmpDamage, damagetype, spellProto);
837
838 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
839 attackerAI->DamageDealt(victim, tmpDamage, damagetype);
840
841 // Hook for OnDamage Event
842 sScriptMgr->OnDamage(attacker, victim, tmpDamage);
843
844 // if any script modified damage, we need to also apply the same modification to unscaled damage value
845 if (tmpDamage != damageTaken)
846 {
847 if (attacker)
848 damageDone = tmpDamage * victim->GetHealthMultiplierForTarget(attacker);
849 else
850 damageDone = tmpDamage;
851
852 damageTaken = tmpDamage;
853 }
854 }
855
856 // Signal to pets that their owner was attacked - except when DOT.
857 if (attacker != victim && damagetype != DOT)
858 {
859 for (Unit* controlled : victim->m_Controlled)
860 if (Creature* cControlled = controlled->ToCreature())
861 if (CreatureAI* controlledAI = cControlled->AI())
862 controlledAI->OwnerAttackedBy(attacker);
863 }
864
865 if (Player* player = victim->ToPlayer())
866 if (player->GetCommandStatus(CHEAT_GOD))
867 return 0;
868
869 if (damagetype != NODAMAGE)
870 {
871 // interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras)
872 if (spellProto)
873 {
876 }
877 else
879
880 if (!damageTaken && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
881 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
882 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
883 if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb))
884 victim->InterruptNonMeleeSpells(false);
885
886 // We're going to call functions which can modify content of the list during iteration over it's elements
887 // Let's copy the list so we can prevent iterator invalidation
889 // copy damage to casters of this aura
890 for (auto i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
891 {
892 // Check if aura was removed during iteration - we don't need to work on such auras
893 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
894 continue;
895 // check damage school mask
896 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
897 continue;
898
899 Unit* shareDamageTarget = (*i)->GetCaster();
900 if (!shareDamageTarget)
901 continue;
902 SpellInfo const* spell = (*i)->GetSpellInfo();
903
904 uint32 share = CalculatePct(damageDone, (*i)->GetAmount());
905
907 Unit::DealDamageMods(attacker, shareDamageTarget, share, nullptr);
908 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
909 }
910 }
911
912 if (!damageDone)
913 return 0;
914
915 uint32 health = victim->GetHealth();
916
917 // duel ends when player has 1 or less hp
918 bool duel_hasEnded = false;
919 bool duel_wasMounted = false;
920 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damageTaken >= (health-1))
921 {
922 if (!attacker)
923 return 0;
924
925 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
926 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
927 damageTaken = health - 1;
928
929 duel_hasEnded = true;
930 }
931 else if (victim->IsCreature() && victim != attacker && damageTaken >= health && victim->ToCreature()->HasFlag(CREATURE_STATIC_FLAG_UNKILLABLE))
932 {
933 damageTaken = health - 1;
934
935 // If we had damage (aka health was not 1 already) trigger OnHealthDepleted
936 if (damageTaken > 0)
937 {
938 if (CreatureAI* victimAI = victim->ToCreature()->AI())
939 victimAI->OnHealthDepleted(attacker, false);
940 }
941 }
942 else if (victim->IsVehicle() && damageTaken >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
943 {
944 Player* victimRider = victim->GetCharmer()->ToPlayer();
945
946 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
947 {
948 if (!attacker)
949 return 0;
950
951 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
952 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
953 damageTaken = health - 1;
954
955 duel_wasMounted = true;
956 duel_hasEnded = true;
957 }
958 }
959
960 if (spellProto && spellProto->HasAttribute(SPELL_ATTR9_CANNOT_KILL_TARGET) && damageTaken >= health)
961 damageTaken = health - 1;
962
963 if (attacker && attacker != victim)
964 {
965 if (Player* killer = attacker->ToPlayer())
966 {
967 // in bg, count dmg if victim is also a player
968 if (victim->GetTypeId() == TYPEID_PLAYER && !(spellProto && spellProto->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD)))
969 if (Battleground* bg = killer->GetBattleground())
970 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damageDone);
971
972 killer->UpdateCriteria(CriteriaType::DamageDealt, health > damageDone ? damageDone : health, 0, 0, victim);
973 killer->UpdateCriteria(CriteriaType::HighestDamageDone, damageDone);
974 }
975 }
976
977 if (victim->GetTypeId() == TYPEID_PLAYER)
979
980 if (victim->GetTypeId() != TYPEID_PLAYER && (!victim->IsControlledByPlayer() || victim->IsVehicle()))
981 {
982 victim->ToCreature()->SetTappedBy(attacker);
983
984 if (!attacker || attacker->IsControlledByPlayer())
985 victim->ToCreature()->LowerPlayerDamageReq(health < damageTaken ? health : damageTaken);
986 }
987
988 bool killed = false;
989 bool skipSettingDeathState = false;
990
991 if (health <= damageTaken)
992 {
993 killed = true;
994
995 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
997
998 if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL))
999 {
1001 std::ranges::stable_sort(vAbsorbOverkill, Trinity::AbsorbAuraOrderPred());
1002 DamageInfo damageInfo = DamageInfo(attacker, victim, damageTaken, spellProto, damageSchoolMask, damagetype,
1003 cleanDamage ? cleanDamage->attackType : BASE_ATTACK);
1004 for (AuraEffect* absorbAurEff : vAbsorbOverkill)
1005 {
1006 Aura* base = absorbAurEff->GetBase();
1007 AuraApplication const* aurApp = base->GetApplicationOfTarget(victim->GetGUID());
1008 if (!aurApp)
1009 continue;
1010
1011 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1012 continue;
1013
1014 // cannot absorb over limit
1015 if (absorbAurEff->GetAmount() > 0)
1016 {
1017 if (damageTaken > absorbAurEff->GetAmount())
1018 continue;
1019 }
1020 else if (damageTaken >= victim->GetMaxHealth() * 2)
1021 continue;
1022
1023 // absorb all damage by default
1024 uint32 currentAbsorb = damageInfo.GetDamage();
1025
1026 // This aura type is used both by Spirit of Redemption (death not really prevented, must grant all credit immediately) and Cheat Death (death prevented)
1027 // repurpose PreventDefaultAction for this
1028 bool deathFullyPrevented = false;
1029
1030 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, currentAbsorb, deathFullyPrevented);
1031
1032 // absorb must be smaller than the damage itself
1033 currentAbsorb = std::min(currentAbsorb, damageInfo.GetDamage());
1034
1035 // if nothing is absorbed (for example because of a scripted cooldown) then skip this aura and proceed with dying
1036 if (!currentAbsorb)
1037 continue;
1038
1039 damageInfo.AbsorbDamage(currentAbsorb);
1040
1041 if (deathFullyPrevented)
1042 killed = false;
1044 skipSettingDeathState = true;
1045
1046 if (currentAbsorb)
1047 {
1049 absorbLog.Attacker = attacker ? attacker->GetGUID() : ObjectGuid::Empty;
1050 absorbLog.Victim = victim->GetGUID();
1051 absorbLog.Caster = base->GetCasterGUID();
1052 absorbLog.AbsorbedSpellID = spellProto ? spellProto->Id : 0;
1053 absorbLog.AbsorbSpellID = base->GetId();
1054 absorbLog.Absorbed = currentAbsorb;
1055 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1056 absorbLog.LogData.Initialize(victim);
1057 victim->SendCombatLogMessage(&absorbLog);
1058 }
1059 }
1060
1061 damageTaken = damageInfo.GetDamage();
1062 }
1063 }
1064
1065 if (spellProto && spellProto->HasAttribute(SPELL_ATTR3_NO_DURABILITY_LOSS))
1066 durabilityLoss = false;
1067
1068 if (killed)
1069 Unit::Kill(attacker, victim, durabilityLoss, skipSettingDeathState);
1070 else
1071 {
1072 if (victim->GetTypeId() == TYPEID_PLAYER)
1074
1075 victim->ModifyHealth(-(int32)damageTaken);
1076
1077 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
1079
1080 if (victim->GetTypeId() != TYPEID_PLAYER)
1081 {
1082 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
1083 if (damagetype != DOT && damageTaken > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
1085
1086 if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT)))
1087 victim->GetThreatManager().AddThreat(attacker, float(damageTaken), spellProto);
1088 }
1089 else // victim is a player
1090 {
1091 // random durability for items (HIT TAKEN)
1092 if (durabilityLoss && roll_chance(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1093 {
1096 }
1097 }
1098
1099 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
1100 {
1101 // random durability for items (HIT DONE)
1102 if (durabilityLoss && roll_chance(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1103 {
1105 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
1106 }
1107 }
1108
1109 if (damagetype != NODAMAGE && damagetype != DOT)
1110 {
1111 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))))
1112 {
1113 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
1114 {
1115 if (spell->getState() == SPELL_STATE_PREPARING)
1116 {
1117 auto isCastInterrupted = [&]()
1118 {
1119 if (!damageTaken)
1120 return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels);
1121
1122 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly))
1123 return true;
1124
1125 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels))
1126 return true;
1127
1128 return false;
1129 };
1130
1131 auto isCastDelayed = [&]()
1132 {
1133 if (!damageTaken)
1134 return false;
1135
1136 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly))
1137 return true;
1138
1139 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushback))
1140 return true;
1141
1142 return false;
1143 };
1144
1145 if (isCastInterrupted())
1146 victim->InterruptSpell(CURRENT_GENERIC_SPELL, false, false);
1147 else if (isCastDelayed())
1148 spell->Delayed();
1149 }
1150 }
1151
1152 if (damageTaken && victim->IsPlayer())
1153 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1154 if (spell->getState() == SPELL_STATE_CHANNELING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration))
1155 spell->DelayedChannel();
1156 }
1157 }
1158
1159 // last damage from duel opponent
1160 if (duel_hasEnded)
1161 {
1162 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
1163
1164 ASSERT_NODEBUGINFO(he && he->duel);
1165
1166 if (duel_wasMounted) // In this case victim == mount
1167 victim->SetHealth(1);
1168 else
1169 he->SetHealth(1);
1170
1171 he->duel->Opponent->CombatStopWithPets(true);
1172 he->CombatStopWithPets(true);
1173
1174 he->CastSpell(he, 7267, true); // beg
1176 }
1177 }
1178
1179 // make player victims stand up automatically
1180 if (victim->GetStandState() && victim->IsPlayer())
1182
1183 return damageTaken;
1184}
1185
1186void Unit::CastStop(uint32 except_spellid)
1187{
1189 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1191}
1192
1193void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
1194{
1195 if (damage < 0)
1196 return;
1197
1198 Unit* victim = damageInfo->target;
1199 if (!victim || !victim->IsAlive())
1200 return;
1201
1202 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1203
1204 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
1206 {
1207 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1208 damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, victim, damage, spellInfo, attackType);
1209
1210 // Per-school calc
1211 switch (spellInfo->DmgClass)
1212 {
1213 // Melee and Ranged Spells
1216 {
1217 if (crit)
1218 {
1219 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1220
1221 // Calculate crit bonus
1222 uint32 crit_bonus = damage;
1223 // Apply crit_damage bonus for melee spells
1224 if (Player* modOwner = GetSpellModOwner())
1225 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritDamageAndHealing, crit_bonus);
1226 damage += crit_bonus;
1227
1228 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1229 float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1230
1231 if (critPctDamageMod != 0)
1232 AddPct(damage, critPctDamageMod);
1233 }
1234
1235 // Spell weapon based damage CAN BE crit & blocked at same time
1236 if (blocked)
1237 {
1238 // double blocked amount if block is critical
1239 uint32 value = victim->GetBlockPercent(GetLevel());
1240 if (victim->IsBlockCritical())
1241 {
1242 value *= 2; // double blocked percent
1244 }
1245
1246 damageInfo->blocked = CalculatePct(damage, value);
1247 if (damage <= int32(damageInfo->blocked))
1248 {
1249 damageInfo->blocked = uint32(damage);
1250 damageInfo->fullBlock = true;
1251 }
1252 damage -= damageInfo->blocked;
1253 }
1254
1255 if (CanApplyResilience())
1256 Unit::ApplyResilience(victim, &damage);
1257 break;
1258 }
1259 // Magical Attacks
1262 {
1263 // If crit add critical bonus
1264 if (crit)
1265 {
1266 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1267 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1268 }
1269
1270 if (CanApplyResilience())
1271 Unit::ApplyResilience(victim, &damage);
1272 break;
1273
1274 }
1275 default:
1276 break;
1277 }
1278 }
1279
1280 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1281 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage, spellInfo);
1282
1283 // Calculate absorb resist
1284 if (damage < 0)
1285 damage = 0;
1286
1287 damageInfo->damage = damage;
1288 damageInfo->originalDamage = damage;
1290 Unit::CalcAbsorbResist(dmgInfo, spell);
1291 damageInfo->absorb = dmgInfo.GetAbsorb();
1292 damageInfo->resist = dmgInfo.GetResist();
1293
1294 if (damageInfo->absorb)
1295 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1296
1297 if (damageInfo->resist)
1298 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1299
1300 damageInfo->damage = dmgInfo.GetDamage();
1301}
1302
1303void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1304{
1305 if (!damageInfo)
1306 return;
1307
1308 Unit* victim = damageInfo->target;
1309 if (!victim)
1310 return;
1311
1312 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1313 return;
1314
1315 if (!damageInfo->Spell)
1316 {
1317 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has no spell");
1318 return;
1319 }
1320
1321 // Call default DealDamage
1322 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1323 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), damageInfo->Spell, durabilityLoss);
1324}
1325
1327void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
1328{
1329 damageInfo->Attacker = this;
1330 damageInfo->Target = victim;
1331
1332 damageInfo->DamageSchoolMask = GetMeleeDamageSchoolMask(attackType);
1333 damageInfo->Damage = 0;
1334 damageInfo->OriginalDamage = 0;
1335 damageInfo->Absorb = 0;
1336 damageInfo->Resist = 0;
1337
1338 damageInfo->Blocked = 0;
1339 damageInfo->HitInfo = 0;
1340 damageInfo->TargetState = 0;
1341 damageInfo->RageGained = 0;
1342
1343 damageInfo->AttackType = attackType;
1344 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1345 damageInfo->ProcVictim = PROC_FLAG_NONE;
1346 damageInfo->CleanDamage = 0;
1347 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1348
1349 if (!victim)
1350 return;
1351
1352 if (!IsAlive() || !victim->IsAlive())
1353 return;
1354
1355 // Select HitInfo/procAttacker/procVictim flag based on attack type
1356 switch (attackType)
1357 {
1358 case BASE_ATTACK:
1361 break;
1362 case OFF_ATTACK:
1365 damageInfo->HitInfo = HITINFO_OFFHAND;
1366 break;
1367 default:
1368 return;
1369 }
1370
1371 // Physical Immune check
1372 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->DamageSchoolMask)))
1373 {
1374 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1375 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1376
1377 damageInfo->Damage = 0;
1378 damageInfo->CleanDamage = 0;
1379 return;
1380 }
1381
1382 uint32 damage = 0;
1383 damage += CalculateDamage(damageInfo->AttackType, false, true);
1384 // Add melee damage bonus
1385 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, nullptr, MECHANIC_NONE, SpellSchoolMask(damageInfo->DamageSchoolMask));
1386 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
1387
1388 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1389 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1390
1391 // Calculate armor reduction
1393 {
1394 damageInfo->Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1395 damageInfo->CleanDamage += damage - damageInfo->Damage;
1396 }
1397 else
1398 damageInfo->Damage = damage;
1399
1400 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1401
1402 switch (damageInfo->HitOutCome)
1403 {
1404 case MELEE_HIT_EVADE:
1406 damageInfo->TargetState = VICTIMSTATE_EVADES;
1407 damageInfo->OriginalDamage = damageInfo->Damage;
1408
1409 damageInfo->Damage = 0;
1410 damageInfo->CleanDamage = 0;
1411 return;
1412 case MELEE_HIT_MISS:
1413 damageInfo->HitInfo |= HITINFO_MISS;
1414 damageInfo->TargetState = VICTIMSTATE_INTACT;
1415 damageInfo->OriginalDamage = damageInfo->Damage;
1416
1417 damageInfo->Damage = 0;
1418 damageInfo->CleanDamage = 0;
1419 break;
1420 case MELEE_HIT_NORMAL:
1421 damageInfo->TargetState = VICTIMSTATE_HIT;
1422 damageInfo->OriginalDamage = damageInfo->Damage;
1423 break;
1424 case MELEE_HIT_CRIT:
1425 {
1426 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1427 damageInfo->TargetState = VICTIMSTATE_HIT;
1428
1429 // Crit bonus calc
1430 damageInfo->Damage *= 2;
1431
1432 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1434
1435 if (mod != 0)
1436 AddPct(damageInfo->Damage, mod);
1437
1438 damageInfo->OriginalDamage = damageInfo->Damage;
1439 break;
1440 }
1441 case MELEE_HIT_PARRY:
1442 damageInfo->TargetState = VICTIMSTATE_PARRY;
1443 damageInfo->CleanDamage += damageInfo->Damage;
1444
1445 damageInfo->OriginalDamage = damageInfo->Damage;
1446 damageInfo->Damage = 0;
1447 break;
1448 case MELEE_HIT_DODGE:
1449 damageInfo->TargetState = VICTIMSTATE_DODGE;
1450 damageInfo->CleanDamage += damageInfo->Damage;
1451
1452 damageInfo->OriginalDamage = damageInfo->Damage;
1453 damageInfo->Damage = 0;
1454 break;
1455 case MELEE_HIT_BLOCK:
1456 damageInfo->TargetState = VICTIMSTATE_HIT;
1457 damageInfo->HitInfo |= HITINFO_BLOCK;
1458 // 30% damage blocked, double blocked amount if block is critical
1459 damageInfo->Blocked = CalculatePct(damageInfo->Damage, damageInfo->Target->GetBlockPercent(GetLevel()));
1460 if (damageInfo->Target->IsBlockCritical())
1461 {
1462 damageInfo->Blocked *= 2;
1464 }
1465
1466 damageInfo->OriginalDamage = damageInfo->Damage;
1467 damageInfo->Damage -= damageInfo->Blocked;
1468 damageInfo->CleanDamage += damageInfo->Blocked;
1469 break;
1470 case MELEE_HIT_GLANCING:
1471 {
1472 damageInfo->HitInfo |= HITINFO_GLANCING;
1473 damageInfo->TargetState = VICTIMSTATE_HIT;
1474 int32 leveldif = int32(victim->GetLevel()) - int32(GetLevel());
1475 if (leveldif > 3)
1476 leveldif = 3;
1477
1478 damageInfo->OriginalDamage = damageInfo->Damage;
1479 float reducePercent = 1.f - leveldif * 0.1f;
1480 damageInfo->CleanDamage += damageInfo->Damage - uint32(reducePercent * damageInfo->Damage);
1481 damageInfo->Damage = uint32(reducePercent * damageInfo->Damage);
1482 break;
1483 }
1484 case MELEE_HIT_CRUSHING:
1485 damageInfo->HitInfo |= HITINFO_CRUSHING;
1486 damageInfo->TargetState = VICTIMSTATE_HIT;
1487 // 150% normal damage
1488 damageInfo->Damage += (damageInfo->Damage / 2);
1489 damageInfo->OriginalDamage = damageInfo->Damage;
1490 break;
1491 default:
1492 break;
1493 }
1494
1495 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1496 if (!(damageInfo->HitInfo & HITINFO_MISS))
1497 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1498
1499 int32 resilienceReduction = damageInfo->Damage;
1500 if (CanApplyResilience())
1501 Unit::ApplyResilience(victim, &resilienceReduction);
1502 resilienceReduction = damageInfo->Damage - resilienceReduction;
1503 damageInfo->Damage -= resilienceReduction;
1504 damageInfo->CleanDamage += resilienceReduction;
1505 damageInfo->OriginalDamage -= resilienceReduction;
1506
1507 // Calculate absorb resist
1508 if (int32(damageInfo->Damage) > 0)
1509 {
1511 // Calculate absorb & resists
1512 DamageInfo dmgInfo(*damageInfo);
1513 Unit::CalcAbsorbResist(dmgInfo);
1514 damageInfo->Absorb = dmgInfo.GetAbsorb();
1515 damageInfo->Resist = dmgInfo.GetResist();
1516
1517 if (damageInfo->Absorb)
1518 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1519
1520 if (damageInfo->Resist)
1521 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1522
1523 damageInfo->Damage = dmgInfo.GetDamage();
1524 }
1525 else // Impossible get negative result but....
1526 damageInfo->Damage = 0;
1527}
1528
1529void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1530{
1531 Unit* victim = damageInfo->Target;
1532
1533 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1534 return;
1535
1536 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1538 {
1539 // Get attack timers
1540 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1541 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1542 // Reduce attack time
1543 if (victim->haveOffhandWeapon() && offtime < basetime)
1544 {
1545 float percent20 = victim->GetBaseAttackTime(OFF_ATTACK) * 0.20f;
1546 float percent60 = 3.0f * percent20;
1547 if (offtime > percent20 && offtime <= percent60)
1548 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1549 else if (offtime > percent60)
1550 {
1551 offtime -= 2.0f * percent20;
1552 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1553 }
1554 }
1555 else
1556 {
1557 float percent20 = victim->GetBaseAttackTime(BASE_ATTACK) * 0.20f;
1558 float percent60 = 3.0f * percent20;
1559 if (basetime > percent20 && basetime <= percent60)
1560 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1561 else if (basetime > percent60)
1562 {
1563 basetime -= 2.0f * percent20;
1564 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1565 }
1566 }
1567 }
1568
1569 // Call default DealDamage
1570 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1571 Unit::DealDamage(this, victim, damageInfo->Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->DamageSchoolMask), nullptr, durabilityLoss);
1572
1573 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1574 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1575 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1576 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1577 {
1578 // 20% base chance
1579 float chance = 20.0f;
1580
1581 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1582 if (victim->GetLevel() < 30)
1583 chance = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
1584
1585 uint32 const victimDefense = victim->GetMaxSkillValueForLevel(this);
1586 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1587
1588 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1589
1590 // -probability is between 0% and 40%
1591 RoundToInterval(chance, 0.0f, 40.0f);
1592 if (roll_chance(chance))
1593 CastSpell(victim, SPELL_DAZED, true);
1594 }
1595
1596 if (GetTypeId() == TYPEID_PLAYER)
1597 {
1598 DamageInfo dmgInfo(*damageInfo);
1599 ToPlayer()->CastItemCombatSpell(dmgInfo);
1600 }
1601
1602 // Do effect if any damage done to target
1603 if (damageInfo->Damage)
1604 {
1605 // We're going to call functions which can modify content of the list during iteration over it's elements
1606 // Let's copy the list so we can prevent iterator invalidation
1608 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1609 {
1610 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1611
1612 // Damage shield can be resisted...
1613 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false, true);
1614 if (missInfo != SPELL_MISS_NONE)
1615 {
1616 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1617 continue;
1618 }
1619
1620 // ...or immuned
1621 if (IsImmunedToDamage(this, spellInfo))
1622 {
1623 victim->SendSpellDamageImmune(this, spellInfo->Id, false);
1624 continue;
1625 }
1626
1627 uint32 damage = aurEff->GetAmountAsInt();
1628 if (Unit* caster = aurEff->GetCaster())
1629 {
1630 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo());
1631 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1632 }
1633
1634 DamageInfo damageInfo(this, victim, damage, spellInfo, spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
1635 victim->CalcAbsorbResist(damageInfo);
1636 damage = damageInfo.GetDamage();
1637 Unit::DealDamageMods(victim, this, damage, nullptr);
1638
1640 damageShield.Attacker = victim->GetGUID();
1641 damageShield.Defender = GetGUID();
1642 damageShield.SpellID = spellInfo->Id;
1643 damageShield.TotalDamage = damage;
1644 damageShield.OriginalDamage = damageInfo.GetOriginalDamage();
1645 damageShield.OverKill = std::max(int32(damage) - int32(GetHealth()), 0);
1646 damageShield.SchoolMask = spellInfo->SchoolMask;
1647 damageShield.LogAbsorbed = damageInfo.GetAbsorb();
1648
1649 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1650
1651 damageShield.LogData.Initialize(this);
1652 victim->SendCombatLogMessage(&damageShield);
1653 }
1654 }
1655}
1656
1657void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinity::IteratorPair<int32 const*> spellVisualKitIds /*= {}*/, int32 sequenceVariation /*= 0*/)
1658{
1660 packet.Guid = GetGUID();
1661 packet.EmoteID = emoteId;
1662
1663 if (EmotesEntry const* emotesEntry = sEmotesStore.LookupEntry(emoteId))
1664 if (emotesEntry->AnimID == ANIM_MOUNT_SPECIAL || emotesEntry->AnimID == ANIM_MOUNT_SELF_SPECIAL)
1665 std::copy(spellVisualKitIds.begin(), spellVisualKitIds.end(), std::back_inserter(packet.SpellVisualKitIDs));
1666
1667 packet.SequenceVariation = sequenceVariation;
1668
1669 if (target)
1670 target->SendDirectMessage(packet.Write());
1671 else
1672 SendMessageToSet(packet.Write(), true);
1673}
1674
1675/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1676{
1677 // only physical spells damage gets reduced by armor
1678 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1679 return false;
1680
1681 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1682}
1683
1684/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1685{
1686 float armor = float(victim->GetArmor());
1687
1688 if (attacker)
1689 {
1690 armor *= victim->GetArmorMultiplierForTarget(attacker);
1691
1692 // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
1693 SpellEffectValue armorBypassPct = 0;
1695 for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i)
1696 if ((*i)->GetCasterGUID() == attacker->GetGUID())
1697 armorBypassPct += (*i)->GetAmount();
1698 armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100.0));
1699
1700 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1702
1703 if (spellInfo)
1704 if (Player* modOwner = attacker->GetSpellModOwner())
1705 modOwner->ApplySpellMod(spellInfo, SpellModOp::TargetResistance, armor);
1706
1708 for (AuraEffect const* aurEff : resIgnoreAuras)
1709 {
1710 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1711 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1712 }
1713
1714 // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
1715 if (attacker->GetTypeId() == TYPEID_PLAYER)
1716 {
1717 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1718
1719 Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
1720 arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
1721 {
1722 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
1723 });
1724
1725 // no more than 100%
1726 RoundToInterval(arpPct, 0.f, 100.f);
1727
1728 float maxArmorPen = 0.f;
1729 if (victim->GetLevelForTarget(attacker) < 60)
1730 maxArmorPen = float(400 + 85 * victim->GetLevelForTarget(attacker));
1731 else
1732 maxArmorPen = 400 + 85 * victim->GetLevelForTarget(attacker) + 4.5f * 85 * (victim->GetLevelForTarget(attacker) - 59);
1733
1734 // Cap armor penetration to this number
1735 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1736 // Figure out how much armor do we ignore
1737 armor -= CalculatePct(maxArmorPen, arpPct);
1738 }
1739 }
1740
1741 if (G3D::fuzzyLe(armor, 0.0f))
1742 return damage;
1743
1744 Classes attackerClass = CLASS_NONE;
1745 Optional<float> attackerItemLevel;
1746 if (attacker)
1747 {
1748 attackerLevel = attacker->GetLevelForTarget(victim);
1749 if (Player const* ownerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
1750 attackerItemLevel = ownerPlayer->m_playerData->AvgItemLevel[AsUnderlyingType(AvgItemLevelCategory::EquippedBase)];
1751 else
1752 attackerClass = Classes(attacker->GetClass());
1753 }
1754
1755 // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
1756 float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, attackerClass, 0);
1757 if (attackerItemLevel)
1758 {
1759 uint32 maxLevelForExpansion = GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION));
1760 if (attackerLevel == maxLevelForExpansion)
1761 {
1762 float itemLevelDelta = *attackerItemLevel - ASSERT_NOTNULL(sItemLevelByLevelTable.GetRow(maxLevelForExpansion))->ItemLevel;
1763 if (uint32 curveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::ArmorItemLevelDiminishing))
1764 armorConstant *= sDB2Manager.GetCurveValueAt(curveId, itemLevelDelta);
1765 }
1766 }
1767
1768 if (!(armor + armorConstant))
1769 return damage;
1770
1771 float mitigation = std::min(armor / (armor + armorConstant), 0.85f);
1772 return uint32(std::max(damage * (1.0f - mitigation), 0.0f));
1773}
1774
1775/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1776{
1777 // Magic damage, check for resists
1778 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1779 return 0;
1780
1781 // Npcs can have holy resistance
1782 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1783 return 0;
1784
1785 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1786 float discreteResistProbability[11] = { };
1787 if (averageResist <= 0.1f)
1788 {
1789 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1790 discreteResistProbability[1] = 5.0f * averageResist;
1791 discreteResistProbability[2] = 2.5f * averageResist;
1792 }
1793 else
1794 {
1795 for (uint32 i = 0; i < 11; ++i)
1796 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1797 }
1798
1799 float roll = rand_norm();
1800 float probabilitySum = 0.0f;
1801
1802 uint32 resistance = 0;
1803 for (; resistance < 11; ++resistance)
1804 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1805 break;
1806
1807 float damageResisted = damage * resistance / 10.f;
1808 if (damageResisted > 0.0f) // if any damage was resisted
1809 {
1810 float ignoredResistance = 0.0f;
1811
1812 if (attacker)
1813 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1814
1815 ignoredResistance = std::min(ignoredResistance, 100.0f);
1816 ApplyPct(damageResisted, 100.0f - ignoredResistance);
1817
1818 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1819 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1820 {
1821 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1822 float armorReduction = damage - damageAfterArmor;
1823
1824 // pick the lower one, the weakest resistance counts
1825 damageResisted = std::min(damageResisted, armorReduction);
1826 }
1827 }
1828
1829 damageResisted = std::max(damageResisted, 0.f);
1830 return uint32(damageResisted);
1831}
1832
1833/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo /*= nullptr*/)
1834{
1835 float victimResistance = float(victim->GetResistance(schoolMask));
1836 if (caster)
1837 {
1838 // pets inherit 100% of masters penetration
1839 if (Player const* player = caster->GetSpellModOwner())
1840 {
1841 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1842 victimResistance -= float(player->GetSpellPenetrationItemMod());
1843 }
1844 else if (Unit const* unitCaster = caster->ToUnit())
1845 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1846 }
1847
1848 // holy resistance exists in pve and comes from level difference, ignore template values
1849 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1850 victimResistance = 0.0f;
1851
1852 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1853 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->Id == 116858)
1854 victimResistance = 0.0f;
1855
1856 victimResistance = std::max(victimResistance, 0.0f);
1857
1858 // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
1859 // gameobject caster -- should it have level based resistance?
1860 if (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
1861 victimResistance += std::max((float(victim->GetLevelForTarget(caster)) - float(caster->GetLevelForTarget(victim))) * 5.0f, 0.0f);
1862
1863 static uint32 const bossLevel = 83;
1864 static float const bossResistanceConstant = 510.0f;
1865 uint32 level = caster ? victim->GetLevelForTarget(caster) : victim->GetLevel();
1866 float resistanceConstant = 0.0f;
1867
1868 if (level == bossLevel)
1869 resistanceConstant = bossResistanceConstant;
1870 else
1871 resistanceConstant = level * 5.0f;
1872
1873 return victimResistance / (victimResistance + resistanceConstant);
1874}
1875
1876/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1877{
1878 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1879 return;
1880
1881 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1882
1883 // Ignore Absorption Auras
1884 float auraAbsorbMod = 0.f;
1885 if (Unit* attacker = damageInfo.GetAttacker())
1887
1888 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1889
1890 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1891
1892 if (spell)
1893 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1894
1895 damageInfo.ResistDamage(resistedDamage);
1896
1897 // We're going to call functions which can modify content of the list during iteration over it's elements
1898 // Let's copy the list so we can prevent iterator invalidation
1900 std::ranges::stable_sort(vSchoolAbsorbCopy, Trinity::AbsorbAuraOrderPred());
1901
1902 // absorb without mana cost
1903 for (auto itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1904 {
1905 AuraEffect* absorbAurEff = *itr;
1906 // Check if aura was removed during iteration - we don't need to work on such auras
1907 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1908 if (!aurApp)
1909 continue;
1910 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1911 continue;
1912
1913 // get amount which can be still absorbed by the aura
1914 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
1915 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1916 if (currentAbsorb < 0)
1917 currentAbsorb = 0;
1918
1920 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1921
1922 uint32 tempAbsorb = uint32(currentAbsorb);
1923
1924 bool defaultPrevented = false;
1925
1926 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1927 currentAbsorb = tempAbsorb;
1928
1929 if (!defaultPrevented)
1930 {
1931 // absorb must be smaller than the damage itself
1932 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1933
1934 damageInfo.AbsorbDamage(currentAbsorb);
1935
1936 tempAbsorb = currentAbsorb;
1937 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1938
1939 // Check if our aura is using amount to count damage
1940 if (absorbAurEff->GetAmount() >= 0)
1941 {
1942 // Reduce shield amount
1943 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1944 // Aura cannot absorb anything more - remove it
1945 if (absorbAurEff->GetAmount() <= 0)
1946 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1947 }
1948 }
1949
1951 damageInfo.ModifyDamage(absorbIgnoringDamage);
1952
1953 if (currentAbsorb)
1954 {
1956 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1957 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1958 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1959 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1960 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1961 absorbLog.Absorbed = currentAbsorb;
1962 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1963 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1964 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
1965 }
1966 }
1967
1968 // absorb by mana cost
1970 for (auto itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1971 {
1972 AuraEffect* absorbAurEff = *itr;
1973 // Check if aura was removed during iteration - we don't need to work on such auras
1974 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1975 if (!aurApp)
1976 continue;
1977 // check damage school mask
1978 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1979 continue;
1980
1981 // get amount which can be still absorbed by the aura
1982 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
1983 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1984 if (currentAbsorb < 0)
1985 currentAbsorb = 0;
1986
1988 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1989
1990 uint32 tempAbsorb = currentAbsorb;
1991
1992 bool defaultPrevented = false;
1993
1994 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1995 currentAbsorb = tempAbsorb;
1996
1997 if (!defaultPrevented)
1998 {
1999 // absorb must be smaller than the damage itself
2000 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
2001
2002 int32 manaReduction = currentAbsorb;
2003
2004 // lower absorb amount by talents
2005 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
2006 manaReduction = int32(float(manaReduction) * manaMultiplier);
2007
2008 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
2009
2010 // take case when mana has ended up into account
2011 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
2012
2013 damageInfo.AbsorbDamage(currentAbsorb);
2014
2015 tempAbsorb = currentAbsorb;
2016 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
2017
2018 // Check if our aura is using amount to count damage
2019 if (absorbAurEff->GetAmount() >= 0)
2020 {
2021 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2022 if ((absorbAurEff->GetAmount() <= 0))
2023 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2024 }
2025 }
2026
2028 damageInfo.ModifyDamage(absorbIgnoringDamage);
2029
2030 if (currentAbsorb)
2031 {
2033 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
2034 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
2035 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
2036 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
2037 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2038 absorbLog.Absorbed = currentAbsorb;
2039 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
2040 absorbLog.LogData.Initialize(damageInfo.GetVictim());
2041 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
2042 }
2043 }
2044
2045 // split damage auras - only when not damaging self
2046 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
2047 {
2048 // We're going to call functions which can modify content of the list during iteration over it's elements
2049 // Let's copy the list so we can prevent iterator invalidation
2051 for (auto itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
2052 {
2053 // Check if aura was removed during iteration - we don't need to work on such auras
2054 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
2055 if (!aurApp)
2056 continue;
2057
2058 // check damage school mask
2059 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
2060 continue;
2061
2062 // Damage can be splitted only if aura has an alive caster
2063 Unit* caster = (*itr)->GetCaster();
2064 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
2065 continue;
2066
2067 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
2068
2069 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
2070
2071 // absorb must be smaller than the damage itself
2072 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
2073
2074 damageInfo.AbsorbDamage(splitDamage);
2075
2076 // check if caster is immune to damage
2077 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
2078 {
2079 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
2080 continue;
2081 }
2082
2083 uint32 split_absorb = 0;
2084 Unit::DealDamageMods(damageInfo.GetAttacker(), caster, splitDamage, &split_absorb);
2085
2086 // sparring
2087 if (Creature* victimCreature = damageInfo.GetVictim()->ToCreature())
2088 {
2089 if (victimCreature->ShouldFakeDamageFrom(damageInfo.GetAttacker()))
2090 damageInfo.ModifyDamage(damageInfo.GetDamage() * -1);
2091 }
2092
2093 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetSpellInfo(), (*itr)->GetBase()->GetSpellVisual(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastId());
2094 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2095 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2096 log.damage = splitDamage;
2097 log.originalDamage = splitDamage;
2098 log.absorb = split_absorb;
2099 caster->SendSpellNonMeleeDamageLog(&log);
2100
2101 // break 'Fear' and similar auras
2103 }
2104 }
2105}
2106
2107/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2108{
2109 if (!healInfo.GetHeal())
2110 return;
2111
2113 std::ranges::stable_sort(vHealAbsorb, Trinity::AbsorbAuraOrderPred());
2114 for (auto i = vHealAbsorb.begin(); i != vHealAbsorb.end() && healInfo.GetHeal() > 0; ++i)
2115 {
2116 AuraEffect* absorbAurEff = *i;
2117 // Check if aura was removed during iteration - we don't need to work on such auras
2118 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(healInfo.GetTarget()->GetGUID());
2119 if (!aurApp)
2120 continue;
2121 if (!(absorbAurEff->GetMiscValue() & healInfo.GetSchoolMask()))
2122 continue;
2123
2124 // get amount which can be still absorbed by the aura
2125 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
2126 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
2127 if (currentAbsorb < 0)
2128 currentAbsorb = 0;
2129
2130 uint32 tempAbsorb = uint32(currentAbsorb);
2131
2132 bool defaultPrevented = false;
2133
2134 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb, defaultPrevented);
2135 currentAbsorb = tempAbsorb;
2136
2137 if (!defaultPrevented)
2138 {
2139 // absorb must be smaller than the heal itself
2140 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(healInfo.GetHeal()));
2141
2142 healInfo.AbsorbHeal(currentAbsorb);
2143
2144 tempAbsorb = currentAbsorb;
2145 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb);
2146
2147 // Check if our aura is using amount to count heal
2148 if (absorbAurEff->GetAmount() >= 0)
2149 {
2150 // Reduce shield amount
2151 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2152 // Aura cannot absorb anything more - remove it
2153 if (absorbAurEff->GetAmount() <= 0)
2154 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2155 }
2156 }
2157
2158 if (currentAbsorb)
2159 {
2161 absorbLog.Healer = healInfo.GetHealer() ? healInfo.GetHealer()->GetGUID() : ObjectGuid::Empty;
2162 absorbLog.Target = healInfo.GetTarget()->GetGUID();
2163 absorbLog.AbsorbCaster = absorbAurEff->GetBase()->GetCasterGUID();
2164 absorbLog.AbsorbedSpellID = healInfo.GetSpellInfo() ? healInfo.GetSpellInfo()->Id : 0;
2165 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2166 absorbLog.Absorbed = currentAbsorb;
2167 absorbLog.OriginalHeal = healInfo.GetOriginalHeal();
2168 absorbLog.LogData.Initialize(healInfo.GetTarget());
2169 healInfo.GetTarget()->SendCombatLogMessage(&absorbLog);
2170 }
2171 }
2172}
2173
2175{
2177 return;
2178
2180 return;
2181
2182 if (IsCreature() && !ToCreature()->CanMelee())
2183 return;
2184
2186 {
2188 if (!channeledSpell || !channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL))
2189 return;
2190 }
2191
2192 Unit* victim = GetVictim();
2193 if (!victim)
2194 return;
2195
2196 auto getAutoAttackError = [&]() -> Optional<AttackSwingErr>
2197 {
2198 if (!IsWithinMeleeRange(victim))
2200
2201 //120 degrees of radiant range, if player is not in boundary radius
2202 if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
2204
2205 return {};
2206 };
2207
2209 {
2210 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2211 if (!autoAttackError)
2212 {
2213 // prevent base and off attack in same time, delay attack at 0.2 sec
2214 if (haveOffhandWeapon())
2217
2218 // do attack
2221 }
2222 else
2224
2225 if (Player* attackerPlayer = ToPlayer())
2226 attackerPlayer->SetAttackSwingError(autoAttackError);
2227 }
2228
2230 {
2231 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2232 if (!autoAttackError)
2233 {
2234 // prevent base and off attack in same time, delay attack at 0.2 sec
2237
2238 // do attack
2241 }
2242 else
2244 }
2245}
2246
2247// Calculates the normalized rage amount per weapon swing
2248static uint32 CalcMeleeAttackRageGain(Unit const* attacker, WeaponAttackType attType)
2249{
2250 if (!attacker || (attType != BASE_ATTACK && attType != OFF_ATTACK))
2251 return 0;
2252
2253 uint32 rage = uint32(attacker->GetBaseAttackTime(attType) / 1000.f * 1.75f);
2254 if (attType == OFF_ATTACK)
2255 rage /= 2;
2256
2257 return rage;
2258}
2259
2260void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2261{
2263 return;
2264
2266 return;
2267
2269 return;
2270
2272 return;
2273
2274 if (!victim->IsAlive())
2275 return;
2276
2277 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2278 return;
2279
2280 AtTargetAttacked(victim, true);
2282
2283 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2284 return; // ignore ranged case
2285
2286 if (!extra && _lastExtraAttackSpell)
2288
2289 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2290 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2292 else
2293 {
2294 // attack can be redirected to another target
2295 victim = GetMeleeHitRedirectTarget(victim);
2296
2298 uint32 meleeAttackSpellId = 0;
2299 if (attType == BASE_ATTACK)
2300 {
2301 if (!meleeAttackOverrides.empty())
2302 meleeAttackSpellId = meleeAttackOverrides.front()->GetSpellEffectInfo().TriggerSpell;
2303 }
2304 else
2305 {
2306 auto itr = std::find_if(meleeAttackOverrides.begin(), meleeAttackOverrides.end(), [&](AuraEffect const* aurEff)
2307 {
2308 return aurEff->GetSpellEffectInfo().MiscValue != 0;
2309 });
2310 if (itr != meleeAttackOverrides.end())
2311 meleeAttackSpellId = (*itr)->GetSpellEffectInfo().MiscValue;
2312 }
2313
2314 if (!meleeAttackSpellId)
2315 {
2316 CalcDamageInfo damageInfo;
2317 CalculateMeleeDamage(victim, &damageInfo, attType);
2318 // Send log damage message to client
2319 Unit::DealDamageMods(damageInfo.Attacker, victim, damageInfo.Damage, &damageInfo.Absorb);
2320
2321 // sparring
2322 if (Creature* victimCreature = victim->ToCreature())
2323 {
2324 if (victimCreature->ShouldFakeDamageFrom(damageInfo.Attacker))
2325 damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
2326 }
2327
2328 // Rage reward
2329 if (this != victim && damageInfo.HitOutCome != MELEE_HIT_MISS && GetPowerType() == POWER_RAGE)
2330 {
2331 if (uint32 rageReward = CalcMeleeAttackRageGain(this, attType))
2332 {
2333 damageInfo.HitInfo |= HITINFO_RAGE_GAIN;
2334 damageInfo.RageGained = RewardRage(rageReward);
2335 }
2336 }
2337
2338 SendAttackStateUpdate(&damageInfo);
2339
2340 _lastDamagedTargetGuid = victim->GetGUID();
2341
2342 DealMeleeDamage(&damageInfo, true);
2343
2344 DamageInfo dmgInfo(damageInfo);
2345 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2346
2347 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2348 GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.Damage, damageInfo.Absorb, damageInfo.Blocked, damageInfo.Resist);
2349 }
2350 else
2351 {
2352 CastSpell(victim, meleeAttackSpellId, true);
2353
2355 if (attType == OFF_ATTACK)
2356 hitInfo |= HITINFO_OFFHAND;
2357
2358 SendAttackStateUpdate(hitInfo, victim, 0, GetMeleeDamageSchoolMask(), 0, 0, 0, VICTIMSTATE_HIT, 0, 0);
2359 }
2360 }
2361}
2362
2364{
2365 while (count)
2366 {
2367 --count;
2368 AttackerStateUpdate(victim, BASE_ATTACK, true);
2369 }
2370}
2371
2373{
2375 if (!targetGUID)
2376 {
2377 ObjectGuid selection = GetTarget();
2378 if (!selection.IsEmpty())
2379 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2380 else
2381 return;
2382 }
2383
2384 extraAttacksTargets[targetGUID] += count;
2385}
2386
2388{
2389 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
2390 return MELEE_HIT_EVADE;
2391
2392 // Miss chance based on melee
2393 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, nullptr) * 100.0f);
2394
2395 // Critical hit chance
2397
2398 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2399 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2400 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2401
2402 // melee attack table implementation
2403 // outcome priority:
2404 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2405 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2406
2407 int32 sum = 0, tmp = 0;
2408 int32 roll = urand(0, 9999);
2409
2410 int32 attackerLevel = GetLevelForTarget(victim);
2411 int32 victimLevel = victim->GetLevelForTarget(this);
2412
2413 // check if attack comes from behind, nobody can parry or block if attacker is behind
2414 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2415
2416 // only creatures can dodge if attacker is behind
2417 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2418
2419 // if victim is casting or cc'd it can't avoid attacks
2420 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2421 {
2422 canDodge = false;
2423 canParryOrBlock = false;
2424 }
2425
2426 // 1. MISS
2427 tmp = miss_chance;
2428 if (tmp > 0 && roll < (sum += tmp))
2429 return MELEE_HIT_MISS;
2430
2431 // always crit against a sitting target (except 0 crit chance)
2432 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2433 return MELEE_HIT_CRIT;
2434
2435 // 2. DODGE
2436 if (canDodge)
2437 {
2438 tmp = dodge_chance;
2439 if (tmp > 0 // check if unit _can_ dodge
2440 && roll < (sum += tmp))
2441 return MELEE_HIT_DODGE;
2442 }
2443
2444 // 3. PARRY
2445 if (canParryOrBlock)
2446 {
2447 tmp = parry_chance;
2448 if (tmp > 0 // check if unit _can_ parry
2449 && roll < (sum += tmp))
2450 return MELEE_HIT_PARRY;
2451 }
2452
2453 // 4. GLANCING
2454 // 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)
2455 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2456 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2457 attackerLevel + 3 < victimLevel)
2458 {
2459 // cap possible value (with bonuses > max skill)
2460 tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100;
2461 if (tmp > 0 && roll < (sum += tmp))
2462 return MELEE_HIT_GLANCING;
2463 }
2464
2465 // 5. BLOCK
2466 if (canParryOrBlock)
2467 {
2468 tmp = block_chance;
2469 if (tmp > 0 // check if unit _can_ block
2470 && roll < (sum += tmp))
2471 return MELEE_HIT_BLOCK;
2472 }
2473
2474 // 6.CRIT
2475 tmp = crit_chance;
2476 if (tmp > 0 && roll < (sum += tmp))
2477 return MELEE_HIT_CRIT;
2478
2479 // 7. CRUSHING
2480 // mobs can score crushing blows if they're 4 or more levels above victim
2481 if (attackerLevel >= victimLevel + 4 &&
2482 // can be from by creature (if can) or from controlled player that considered as creature
2485 {
2486 // add 2% chance per level, min. is 15%
2487 tmp = attackerLevel - victimLevel * 1000 - 1500;
2488 if (roll < (sum += tmp))
2489 {
2490 TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <{}, {})", sum-tmp, sum);
2491 return MELEE_HIT_CRUSHING;
2492 }
2493 }
2494
2495 // 8. HIT
2496 return MELEE_HIT_NORMAL;
2497}
2498
2499uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
2500{
2501 float minDamage = 0.0f;
2502 float maxDamage = 0.0f;
2503
2504 if (normalized || !addTotalPct)
2505 {
2506 CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
2507 if (IsInFeralForm() && attType == BASE_ATTACK)
2508 {
2509 float minOffhandDamage = 0.0f;
2510 float maxOffhandDamage = 0.0f;
2511 CalculateMinMaxDamage(OFF_ATTACK, normalized, addTotalPct, minOffhandDamage, maxOffhandDamage);
2512 minDamage += minOffhandDamage;
2513 maxDamage += maxOffhandDamage;
2514 }
2515 }
2516 else
2517 {
2518 switch (attType)
2519 {
2520 case RANGED_ATTACK:
2521 minDamage = m_unitData->MinRangedDamage;
2522 maxDamage = m_unitData->MaxRangedDamage;
2523 break;
2524 case BASE_ATTACK:
2525 minDamage = m_unitData->MinDamage;
2526 maxDamage = m_unitData->MaxDamage;
2527 if (IsInFeralForm())
2528 {
2529 minDamage += m_unitData->MinOffHandDamage;
2530 maxDamage += m_unitData->MaxOffHandDamage;
2531 }
2532 break;
2533 case OFF_ATTACK:
2534 minDamage = m_unitData->MinOffHandDamage;
2535 maxDamage = m_unitData->MaxOffHandDamage;
2536 break;
2537 default:
2538 break;
2539 }
2540 }
2541
2542 minDamage = std::max(0.f, minDamage);
2543 maxDamage = std::max(0.f, maxDamage);
2544
2545 if (minDamage > maxDamage)
2546 std::swap(minDamage, maxDamage);
2547
2548 return urand(uint32(minDamage), uint32(maxDamage));
2549}
2550
2552{
2554 packet.Attacker = GetGUID();
2555 packet.Victim = victim->GetGUID();
2556 SendMessageToSet(packet.Write(), true);
2557}
2558
2560{
2562 attackStop.Attacker = GetGUID();
2563 if (victim)
2564 {
2565 attackStop.Victim = victim->GetGUID();
2566 attackStop.NowDead = !victim->IsAlive();
2567 }
2568
2569 SendMessageToSet(attackStop.Write(), true);
2570
2571 if (victim)
2572 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2573 else
2574 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2575}
2576
2578{
2580 return true;
2581 return false;
2582}
2583
2584float Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const
2585{
2586 if (!spellInfo)
2587 return 0;
2588
2589 float resistMech = 0;
2590 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2591 {
2592 if (!effect.IsEffect())
2593 break;
2594
2595 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2596 if (effectMech)
2597 {
2599 if (resistMech < temp)
2600 resistMech = temp;
2601 }
2602 }
2603
2604 return std::max(resistMech, 0.0f);
2605}
2606
2607bool Unit::CanUseAttackType(uint8 attacktype) const
2608{
2609 switch (attacktype)
2610 {
2611 case BASE_ATTACK:
2613 case OFF_ATTACK:
2615 case RANGED_ATTACK:
2617 default:
2618 return true;
2619 }
2620}
2621
2622// Melee based spells hit result calculations
2624{
2625 if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE))
2626 return SPELL_MISS_NONE;
2627
2628 WeaponAttackType attType = BASE_ATTACK;
2629
2630 // Check damage class instead of attack type to correctly handle judgements
2631 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2632 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2633 attType = RANGED_ATTACK;
2634
2635 uint32 roll = urand(0, 9999);
2636
2637 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo) * 100.0f);
2638
2639 // Roll miss
2640 uint32 tmp = missChance;
2641 if (roll < tmp)
2642 return SPELL_MISS_MISS;
2643
2644 // Chance resist mechanic
2645 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100.0f;
2646 tmp += resist_chance;
2647 if (roll < tmp)
2648 return SPELL_MISS_RESIST;
2649
2650 // Same spells cannot be parried/dodged
2652 return SPELL_MISS_NONE;
2653
2654 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
2655 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
2656 bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
2657
2658 // if victim is casting or cc'd it can't avoid attacks
2659 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2660 {
2661 canDodge = false;
2662 canParry = false;
2663 canBlock = false;
2664 }
2665
2666 // Ranged attacks can only miss, resist and deflect and get blocked
2667 if (attType == RANGED_ATTACK)
2668 {
2669 canParry = false;
2670 canDodge = false;
2671
2672 // only if in front
2673 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2674 {
2675 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100.0f;
2676 tmp += deflect_chance;
2677 if (roll < tmp)
2678 return SPELL_MISS_DEFLECT;
2679 }
2680 }
2681
2682 // Check for attack from behind
2683 if (!victim->HasInArc(float(M_PI), this))
2684 {
2686 {
2687 // Can't dodge from behind in PvP (but its possible in PvE)
2688 if (victim->GetTypeId() == TYPEID_PLAYER)
2689 canDodge = false;
2690 // Can't parry or block
2691 canParry = false;
2692 canBlock = false;
2693 }
2694 else // Only deterrence as of 3.3.5
2695 {
2697 canParry = false;
2698 }
2699 }
2700
2701 // Ignore combat result aura
2703 for (AuraEffect const* aurEff : ignore)
2704 {
2705 if (!aurEff->IsAffectingSpell(spellInfo))
2706 continue;
2707
2708 switch (aurEff->GetMiscValue())
2709 {
2710 case MELEE_HIT_DODGE:
2711 canDodge = false;
2712 break;
2713 case MELEE_HIT_BLOCK:
2714 canBlock = false;
2715 break;
2716 case MELEE_HIT_PARRY:
2717 canParry = false;
2718 break;
2719 default:
2720 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2721 break;
2722 }
2723 }
2724
2725 if (canDodge)
2726 {
2727 // Roll dodge
2728 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2729 if (dodgeChance < 0)
2730 dodgeChance = 0;
2731
2732 if (roll < (tmp += dodgeChance))
2733 return SPELL_MISS_DODGE;
2734 }
2735
2736 if (canParry)
2737 {
2738 // Roll parry
2739 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2740 if (parryChance < 0)
2741 parryChance = 0;
2742
2743 tmp += parryChance;
2744 if (roll < tmp)
2745 return SPELL_MISS_PARRY;
2746 }
2747
2748 if (canBlock)
2749 {
2750 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2751 if (blockChance < 0)
2752 blockChance = 0;
2753 tmp += blockChance;
2754
2755 if (roll < tmp)
2756 return SPELL_MISS_BLOCK;
2757 }
2758
2759 return SPELL_MISS_NONE;
2760}
2761
2762float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2763{
2764 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2765
2766 float chance = 0.0f;
2767 float levelBonus = 0.0f;
2768 if (Player const* playerVictim = victim->ToPlayer())
2769 chance = playerVictim->m_activePlayerData->DodgePercentage;
2770 else
2771 {
2772 if (!victim->IsTotem())
2773 {
2774 chance = 3.0f;
2776
2777 if (levelDiff > 0)
2778 levelBonus = 1.5f * levelDiff;
2779 }
2780 }
2781
2782 chance += levelBonus;
2783
2784 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2786
2787 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2789
2790 // Reduce dodge chance by attacker expertise rating
2791 if (GetTypeId() == TYPEID_PLAYER)
2792 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2793 else
2795 return std::max(chance, 0.0f);
2796}
2797
2798float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2799{
2800 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2801
2802 float chance = 0.0f;
2803 float levelBonus = 0.0f;
2804 if (Player const* playerVictim = victim->ToPlayer())
2805 {
2806 if (playerVictim->CanParry())
2807 {
2808 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2809 if (!tmpitem)
2810 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2811
2812 if (tmpitem)
2813 chance = playerVictim->m_activePlayerData->ParryPercentage;
2814 }
2815 }
2816 else
2817 {
2819 {
2820 chance = 6.0f;
2822
2823 if (levelDiff > 0)
2824 levelBonus = 1.5f * levelDiff;
2825 }
2826 }
2827
2828 chance += levelBonus;
2829
2830 // Reduce parry chance by attacker expertise rating
2831 if (GetTypeId() == TYPEID_PLAYER)
2832 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2833 else
2835 return std::max(chance, 0.0f);
2836}
2837
2839{
2840 float miss_chance = 5.0f;
2841
2842 return miss_chance;
2843}
2844
2845float Unit::GetUnitBlockChance(WeaponAttackType /*attType*/, Unit const* victim) const
2846{
2847 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2848
2849 float chance = 0.0f;
2850 float levelBonus = 0.0f;
2851 if (Player const* playerVictim = victim->ToPlayer())
2852 {
2853 if (playerVictim->CanBlock())
2854 {
2855 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2856 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD)
2857 chance = playerVictim->m_activePlayerData->BlockPercentage;
2858 }
2859 }
2860 else
2861 {
2863 {
2864 chance = 3.0f;
2866
2867 if (levelDiff > 0)
2868 levelBonus = 1.5f * levelDiff;
2869 }
2870 }
2871
2872 chance += levelBonus;
2873 return std::max(chance, 0.0f);
2874}
2875
2877{
2878 float chance = 0.0f;
2879 if (Player const* thisPlayer = ToPlayer())
2880 {
2881 switch (attackType)
2882 {
2883 case BASE_ATTACK:
2884 chance = thisPlayer->m_activePlayerData->CritPercentage;
2885 break;
2886 case OFF_ATTACK:
2887 chance = thisPlayer->m_activePlayerData->OffhandCritPercentage;
2888 break;
2889 case RANGED_ATTACK:
2890 chance = thisPlayer->m_activePlayerData->RangedCritPercentage;
2891 break;
2892 // Just for good manner
2893 default:
2894 chance = 0.0f;
2895 break;
2896 }
2897 }
2898 else
2899 {
2900 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2901 {
2902 chance = 5.0f;
2905 }
2906 }
2907
2908 return chance;
2909}
2910
2911float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2912{
2913 float chance = critDone;
2914
2915 // flat aura mods
2916 if (attackType != RANGED_ATTACK)
2918
2920 {
2921 return !HealthBelowPct(aurEff->GetMiscValueB());
2922 });
2923
2924 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool
2925 {
2926 return aurEff->GetCasterGUID() == attacker->GetGUID();
2927 });
2928
2929 if (TempSummon const* tempSummon = attacker->ToTempSummon())
2930 {
2931 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
2932 {
2933 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
2934 });
2935 }
2936
2938
2939 return std::max(chance, 0.0f);
2940}
2941
2942float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2943{
2944 float chance = GetUnitCriticalChanceDone(attackType);
2945 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2946}
2947
2949{
2950 while (!m_removedAuras.empty())
2951 {
2952 delete m_removedAuras.front();
2953 m_removedAuras.pop_front();
2954 }
2955
2957}
2958
2960{
2961 if (!_spellHistory->IsPaused())
2962 _spellHistory->Update();
2963
2966
2967 // remove finished spells from current pointers
2968 for (Spell*& spell : m_currentSpells)
2969 {
2970 if (spell && spell->getState() == SPELL_STATE_FINISHED)
2971 {
2972 spell->SetReferencedFromCurrent(false);
2973 spell = nullptr; // remove pointer
2974 }
2975 }
2976
2977 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2979 {
2980 Aura* i_aura = m_auraUpdateIterator->second;
2981 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2982 i_aura->UpdateOwner(time, this);
2983 }
2984
2985 // remove expired auras - do that after updates(used in scripts?)
2986 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2987 {
2988 if (i->second->IsExpired())
2990 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2991 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2992 else
2993 ++i;
2994 }
2995
2996 for (AuraApplication* visibleAura : m_visibleAurasToUpdate)
2997 visibleAura->ClientUpdate();
2998
2999 m_visibleAurasToUpdate.clear();
3000
3002
3003 if (!m_gameObj.empty())
3004 {
3005 GameObjectList::iterator itr;
3006 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
3007 {
3008 if (!(*itr)->isSpawned())
3009 {
3010 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
3011 (*itr)->SetRespawnTime(0);
3012 (*itr)->Delete();
3013 m_gameObj.erase(itr++);
3014 }
3015 else
3016 ++itr;
3017 }
3018 }
3019}
3020
3022{
3023 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
3024
3026 return;
3027
3028 // check "realtime" interrupts
3029 // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
3030 if ((isMoving() && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckMovement() != SPELL_CAST_OK) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->Id == 75))
3031 {
3032 // cancel wand shoot
3033 if (autoRepeatSpellInfo->Id != 75)
3035 return;
3036 }
3037
3038 // castroutine
3040 {
3041 // Check if able to cast
3042 SpellCastResult result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true);
3043 if (result != SPELL_CAST_OK)
3044 {
3045 if (autoRepeatSpellInfo->Id != 75)
3047 else if (GetTypeId() == TYPEID_PLAYER)
3048 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_SpellVisual, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_castId, result);
3049
3050 return;
3051 }
3052
3053 // we want to shoot
3054 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_IGNORE_GCD);
3056 }
3057}
3058
3063
3068
3070{
3071 int32 index = m_unitData->ChannelObjects.FindIndex(guid);
3072 if (index >= 0)
3074}
3075
3080
3082{
3083 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3084
3085 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
3086
3087 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
3088 return;
3089
3090 // special breakage effects:
3091 switch (CSpellType)
3092 {
3094 {
3096
3097 // generic spells always break channeled not delayed spells
3102
3103 // autorepeat breaking
3105 {
3106 // break autorepeat if not Auto Shot
3107 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
3109 }
3110 if (pSpell->GetCastTime() > 0)
3112
3113 break;
3114 }
3116 {
3117 // channel spells always break generic non-delayed and any channeled spells
3120
3121 // it also does break autorepeat if not Auto Shot
3123 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
3126
3127 break;
3128 }
3130 {
3131 if (m_currentSpells[CSpellType] && m_currentSpells[CSpellType]->getState() == SPELL_STATE_IDLE)
3132 m_currentSpells[CSpellType]->setState(SPELL_STATE_FINISHED);
3133
3134 // only Auto Shoot does not break anything
3135 if (pSpell->GetSpellInfo()->Id != 75)
3136 {
3137 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3140 }
3141
3142 break;
3143 }
3144 default:
3145 break; // other spell types don't break anything now
3146 }
3147
3148 // current spell (if it is still here) may be safely deleted now
3149 if (m_currentSpells[CSpellType])
3150 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3151
3152 // set new current spell
3153 m_currentSpells[CSpellType] = pSpell;
3154 pSpell->SetReferencedFromCurrent(true);
3155
3156 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3157}
3158
3159void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
3160{
3161 //TC_LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
3162 Spell* spell = m_currentSpells[spellType];
3163 if (spell
3164 && (withDelayed || spell->getState() != SPELL_STATE_LAUNCHED)
3165 && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CHANNELING))
3166 {
3167 // for example, do not let self-stun aura interrupt itself
3168 if (!spell->IsInterruptable())
3169 return;
3170
3171 // send autorepeat cancel message for autorepeat spells
3172 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3173 if (GetTypeId() == TYPEID_PLAYER)
3175
3176 if (spell->getState() != SPELL_STATE_FINISHED)
3177 spell->cancel();
3178 else
3179 {
3180 m_currentSpells[spellType] = nullptr;
3181 spell->SetReferencedFromCurrent(false);
3182 }
3183
3184 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
3185 ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo());
3186 }
3187}
3188
3189void Unit::FinishSpell(CurrentSpellTypes spellType, SpellCastResult result /*= SPELL_CAST_OK*/)
3190{
3191 Spell* spell = m_currentSpells[spellType];
3192 if (!spell)
3193 return;
3194
3195 if (spellType == CURRENT_CHANNELED_SPELL)
3196 spell->SendChannelUpdate(0, result);
3197
3198 spell->finish(result);
3199}
3200
3201bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
3202{
3203 // We don't do loop here to explicitly show that melee spell is excluded.
3204 // Maybe later some special spells will be excluded too.
3205
3206 // generic spells are cast when they are not finished and not delayed
3209 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_LAUNCHED))
3210 {
3211 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3212 {
3213 if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3214 return true;
3215 }
3216 }
3217 // channeled spells may be delayed, but they are still considered cast
3218 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3220 {
3221 if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3222 return true;
3223 }
3224 // autorepeat spells may be finished or delayed, but they are still considered cast
3225 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3226 return true;
3227
3228 return false;
3229}
3230
3231void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3232{
3233 // generic spells are interrupted if they are not finished or delayed
3234 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3235 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3236
3237 // autorepeat spells are interrupted if they are not finished or delayed
3238 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3239 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3240
3241 // channeled spells are interrupted if they are not finished, even if they are delayed
3242 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3244}
3245
3247{
3248 for (Spell* spell : m_currentSpells)
3249 if (spell && spell->m_spellInfo->Id == spell_id)
3250 return spell;
3251 return nullptr;
3252}
3253
3255{
3256 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3257 return spell->GetCastTime();
3258 return 0;
3259}
3260
3262{
3263 // can always move when not casting
3265 return false;
3266
3268 if (CanCastSpellWhileMoving(spell->GetSpellInfo()) || spell->getState() == SPELL_STATE_FINISHED ||
3269 !spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
3270 return false;
3271
3272 // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
3274 if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
3275 if (spell->GetSpellInfo()->IsMoveAllowedChannel() || CanCastSpellWhileMoving(spell->GetSpellInfo()))
3276 return false;
3277
3278 // prohibit movement for all other spell casts
3279 return true;
3280}
3281
3282bool Unit::CanCastSpellWhileMoving(SpellInfo const* spellInfo) const
3283{
3285 return false;
3286
3288 return true;
3289
3291 return true;
3292
3293 for (uint32 label : spellInfo->Labels)
3295 return true;
3296
3297 return false;
3298}
3299
3300bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3301{
3302 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3303}
3304
3305bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3306{
3307 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3308}
3309
3311{
3312 // Aquatic creatures are not allowed to leave liquids
3313 if (!IsInWater() && c->IsAquatic())
3314 return false;
3315
3316 // Underwater special case. Some creatures may not go below liquid surfaces
3317 if (IsUnderWater() && c->CannotPenetrateWater())
3318 return false;
3319
3320 // Water checks
3321 if (IsInWater() && !c->CanEnterWater())
3322 return false;
3323
3324 // Some creatures are tied to the ocean floor and cannot chase swimming targets.
3326 return false;
3327
3328 return true;
3329}
3330
3335
3337{
3339}
3340
3342{
3344}
3345
3352
3354{
3355 if (!IsControlledByPlayer())
3356 return;
3357
3358 // remove appropriate auras if we are swimming/not swimming respectively
3359 if (IsInWater())
3361 else
3363
3364 // liquid aura handling
3365 LiquidTypeEntry const* curLiquid = nullptr;
3366 if (IsInWater() && newLiquidData)
3367 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3368 if (curLiquid != _lastLiquid)
3369 {
3372
3373 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3374 _lastLiquid = curLiquid;
3375
3377 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3378 CastSpell(this, curLiquid->SpellID, true);
3379 }
3380}
3381
3386
3388{
3389 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3390
3391 // Check if these can stack anyway
3392 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3393 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3394
3395 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3396 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3397 {
3398 // check if cast item changed
3399 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3400
3401 // find current aura from spell and change it's stackamount, or refresh it's duration
3402 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))
3403 {
3404 // effect masks do not match
3405 // extremely rare case
3406 // let's just recreate aura
3407 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3408 return nullptr;
3409
3410 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3411 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3412 {
3413 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3414 if (!auraEff)
3415 continue;
3416
3418 if (createInfo.BaseAmount)
3419 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3420 else
3421 bp = spellEffectInfo.BasePoints;
3422
3423 SpellEffectValue* oldBP = const_cast<SpellEffectValue*>(&(auraEff->m_baseAmount));
3424 if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::AuraPointsStack))
3425 *oldBP += bp;
3426 else
3427 *oldBP = bp;
3428 }
3429
3430 // correct cast item guid if needed
3431 if (castItemGUID != foundAura->GetCastItemGUID())
3432 {
3433 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3434 *oldGUID = castItemGUID;
3435 uint32* oldItemId = const_cast<uint32*>(&foundAura->m_castItemId);
3436 *oldItemId = createInfo.CastItemId;
3437 int32* oldItemLevel = const_cast<int32*>(&foundAura->m_castItemLevel);
3438 *oldItemLevel = createInfo.CastItemLevel;
3439 }
3440
3441 // try to increase stack amount
3442 foundAura->ModStackAmount(createInfo.StackAmount, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3443 return foundAura;
3444 }
3445 }
3446
3447 return nullptr;
3448}
3449
3450void Unit::_AddAura(UnitAura* aura, Unit* caster)
3451{
3453 m_ownedAuras.emplace(aura->GetId(), aura);
3454
3455 _RemoveNoStackAurasDueToAura(aura, true);
3456
3457 if (aura->IsRemoved())
3458 return;
3459
3460 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3461 if (aura->IsSingleTarget())
3462 {
3464 /* @HACK: Player is not in world during loading auras.
3465 * Single target auras are not saved or loaded from database
3466 * but may be created as a result of aura links.
3467 */
3468
3469 std::vector<Aura*> aurasSharingLimit;
3470 // remove other single target auras
3471 for (Aura* scAura : caster->GetSingleCastAuras())
3472 if (scAura->IsSingleTargetWith(aura))
3473 aurasSharingLimit.push_back(scAura);
3474
3475 // register single target aura
3476 caster->GetSingleCastAuras().push_front(aura);
3477
3478 uint32 maxOtherAuras = aura->GetSpellInfo()->MaxAffectedTargets - 1;
3479 while (aurasSharingLimit.size() > maxOtherAuras)
3480 {
3481 aurasSharingLimit.back()->Remove();
3482 aurasSharingLimit.pop_back();
3483 }
3484 }
3485}
3486
3487// creates aura application instance and registers it in lists
3488// aura application effects are handled separately to prevent aura list corruption
3490{
3491 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3493
3494 // just return if the aura has been already removed
3495 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3496 if (aura->IsRemoved())
3497 {
3498 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());
3499 return nullptr;
3500 }
3501
3502 // aura mustn't be already applied on target
3503 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3504
3505 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3506 uint32 aurId = aurSpellInfo->Id;
3507
3508 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3509 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3510 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3511 return nullptr;
3512
3513 Unit* caster = aura->GetCaster();
3514
3515 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3516 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3517
3518 if (aurSpellInfo->HasAnyAuraInterruptFlag())
3519 {
3520 m_interruptableAuras.push_front(aurApp);
3521 AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2);
3522 }
3523
3524 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3525 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3526
3527 aura->_ApplyForTarget(this, caster, aurApp);
3528 return aurApp;
3529}
3530
3531void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3532{
3533 ASSERT(aura);
3534 ASSERT(aura->HasEffect(effIndex));
3536 ASSERT(aurApp);
3537 if (!aurApp->GetEffectMask())
3538 _ApplyAura(aurApp, 1 << effIndex);
3539 else
3540 aurApp->_HandleEffect(effIndex, true);
3541}
3542
3543// handles effects of aura application
3544// should be done after registering aura in lists
3546{
3547 Aura* aura = aurApp->GetBase();
3548
3549 _RemoveNoStackAurasDueToAura(aura, false);
3550
3551 if (aurApp->GetRemoveMode())
3552 return;
3553
3554 // Update target aura state flag
3555 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3556 {
3557 uint32 aStateMask = (1 << (aState - 1));
3558 // force update so the new caster registers it
3559 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && *m_unitData->AuraState & aStateMask)
3561 else
3562 ModifyAuraState(aState, true);
3563 }
3564
3565 if (aurApp->GetRemoveMode())
3566 return;
3567
3568 // Sitdown on apply aura req seated
3571
3572 Unit* caster = aura->GetCaster();
3573
3574 if (aurApp->GetRemoveMode())
3575 return;
3576
3577 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3578
3579 // apply effects of the aura
3580 for (AuraEffect const* aurEff : aura->GetAuraEffects())
3581 {
3582 if (effMask & 1 << aurEff->GetEffIndex())
3583 {
3584 aurApp->_HandleEffect(aurEff->GetEffIndex(), true);
3585 if (aurApp->GetRemoveMode())
3586 break;
3587 }
3588 }
3589
3590 if (Player* player = ToPlayer())
3591 {
3592 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aura->GetId()))
3593 player->UpdateVisibleObjectInteractions(false, true, false, false);
3594
3595 player->FailCriteria(CriteriaFailEvent::GainAura, aura->GetId());
3596 player->StartCriteria(CriteriaStartEvent::GainAura, aura->GetId());
3597 player->UpdateCriteria(CriteriaType::GainAura, aura->GetId(), 0, 0, caster);
3598 }
3599}
3600
3601// removes aura application from lists and unapplies effects
3602void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3603{
3604 AuraApplication * aurApp = i->second;
3605 ASSERT(aurApp);
3606 ASSERT(!aurApp->GetRemoveMode());
3607 ASSERT(aurApp->GetTarget() == this);
3608
3609 aurApp->SetRemoveMode(removeMode);
3610 Aura* aura = aurApp->GetBase();
3611 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3612
3613 // dead loop is killing the server probably
3614 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3615
3617
3618 Unit* caster = aura->GetCaster();
3619
3620 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3621 m_appliedAuras.erase(i);
3622
3624 {
3627 }
3628
3629 bool auraStateFound = false;
3630 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3631 if (auraState)
3632 {
3633 bool canBreak = false;
3634 // Get mask of all aurastates from remaining auras
3635 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3636 {
3637 if (itr->second == aurApp)
3638 {
3639 m_auraStateAuras.erase(itr);
3640 itr = m_auraStateAuras.lower_bound(auraState);
3641 canBreak = true;
3642 continue;
3643 }
3644 auraStateFound = true;
3645 ++itr;
3646 }
3647 }
3648
3649 aurApp->_Remove();
3650 aura->_UnapplyForTarget(this, caster, aurApp);
3651
3652 // remove effects of the spell - needs to be done after removing aura from lists
3653 for (AuraEffect const* aurEff : aura->GetAuraEffects())
3654 if (aurApp->HasEffect(aurEff->GetEffIndex()))
3655 aurApp->_HandleEffect(aurEff->GetEffIndex(), false);
3656
3657 // all effect mustn't be applied
3658 ASSERT(!aurApp->GetEffectMask());
3659
3660 // Remove totem at next update if totem loses its aura
3661 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3662 {
3663 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3665 }
3666
3667 // Remove aurastates only if needed and were not found
3668 if (auraState)
3669 {
3670 if (!auraStateFound)
3671 ModifyAuraState(auraState, false);
3672 else
3673 {
3674 // update for casters, some shouldn't 'see' the aura state
3675 uint32 aStateMask = (1 << (auraState - 1));
3676 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3678 }
3679 }
3680
3681 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3682
3683 if (Player* player = ToPlayer())
3684 {
3685 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3686 player->UpdateVisibleObjectInteractions(false, true, false, false);
3687
3688 player->FailCriteria(CriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId());
3689 }
3690
3691 i = m_appliedAuras.begin();
3692}
3693
3695{
3696 // aura can be removed from unit only if it's applied on it, shouldn't happen
3697 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3698
3699 uint32 spellId = aurApp->GetBase()->GetId();
3700 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3701
3702 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3703 {
3704 if (iter->second == aurApp)
3705 {
3706 _UnapplyAura(iter, removeMode);
3707 return;
3708 }
3709 else
3710 ++iter;
3711 }
3712 ABORT();
3713}
3714
3716{
3717 SpellInfo const* spellProto = aura->GetSpellInfo();
3718
3719 // passive spell special case (only non stackable with ranks)
3720 if (spellProto->IsPassiveStackableWithRanks())
3721 return;
3722
3723 if (!IsHighestExclusiveAura(aura))
3724 {
3725 aura->Remove();
3726 return;
3727 }
3728
3729 if (owned)
3730 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3731 else
3732 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3733}
3734
3735void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
3736{
3737 if (apply)
3738 {
3739 m_modAuras[aurEff->GetAuraType()].push_front(aurEff);
3740 if (Player* player = ToPlayer())
3741 {
3742 player->FailCriteria(CriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType());
3743 player->StartCriteria(CriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType());
3744 }
3745 }
3746 else
3748}
3749
3750// All aura base removes should go through this function!
3751void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3752{
3753 Aura* aura = i->second;
3754 ASSERT(!aura->IsRemoved());
3755
3756 // if unit currently update aura list then make safe update iterator shift to next
3757 if (m_auraUpdateIterator == i)
3759
3760 m_ownedAuras.erase(i);
3761 m_removedAuras.push_front(aura);
3762
3763 // Unregister single target aura
3764 if (aura->IsSingleTarget())
3765 aura->UnregisterSingleTarget();
3766
3767 aura->_Remove(removeMode);
3768
3769 i = m_ownedAuras.begin();
3770}
3771
3772void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3773{
3774 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3775 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3776 {
3777 RemoveOwnedAura(itr, removeMode);
3778 itr = m_ownedAuras.lower_bound(spellId);
3779 }
3780 else
3781 ++itr;
3782}
3783
3785{
3786 if (aura->IsRemoved())
3787 return;
3788
3789 ASSERT(aura->GetOwner() == this);
3790
3791 if (removeMode == AURA_REMOVE_NONE)
3792 {
3793 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3794 return;
3795 }
3796
3797 uint32 spellId = aura->GetId();
3798 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3799
3800 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3801 {
3802 if (itr->second == aura)
3803 {
3804 RemoveOwnedAura(itr, removeMode);
3805 return;
3806 }
3807 }
3808
3809 ABORT();
3810}
3811
3812Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, Aura* except) const
3813{
3814 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3815 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3816 {
3817 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3818 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3819 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3820 && (!except || except != itr->second))
3821 {
3822 return itr->second;
3823 }
3824 }
3825 return nullptr;
3826}
3827
3828void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3829{
3830 AuraApplication * aurApp = i->second;
3831 // Do not remove aura which is already being removed
3832 if (aurApp->GetRemoveMode())
3833 return;
3834 Aura* aura = aurApp->GetBase();
3835 _UnapplyAura(i, mode);
3836 // Remove aura - for Area and Target auras
3837 if (aura->GetOwner() == this)
3838 aura->Remove(mode);
3839}
3840
3841void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint32 reqEffMask, AuraRemoveMode removeMode)
3842{
3843 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3844 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3845 {
3846 Aura const* aura = iter->second->GetBase();
3847 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3848 && (!caster || aura->GetCasterGUID() == caster))
3849 {
3850 RemoveAura(iter, removeMode);
3851 return;
3852 }
3853 else
3854 ++iter;
3855 }
3856}
3857
3859{
3860 // we've special situation here, RemoveAura called while during aura removal
3861 // this kind of call is needed only when aura effect removal handler
3862 // or event triggered by it expects to remove
3863 // not yet removed effects of an aura
3864 if (aurApp->GetRemoveMode())
3865 {
3866 // remove remaining effects of an aura
3867 for (AuraEffect const* aurEff : aurApp->GetBase()->GetAuraEffects())
3868 {
3869 if (aurApp->HasEffect(aurEff->GetEffIndex()))
3870 aurApp->_HandleEffect(aurEff->GetEffIndex(), false);
3871 }
3872 return;
3873 }
3874 // no need to remove
3875 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3876 return;
3877
3878 uint32 spellId = aurApp->GetBase()->GetId();
3879 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3880
3881 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3882 {
3883 if (aurApp == iter->second)
3884 {
3885 RemoveAura(iter, mode);
3886 return;
3887 }
3888 else
3889 ++iter;
3890 }
3891}
3892
3894{
3895 if (aura->IsRemoved())
3896 return;
3897 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3898 RemoveAura(aurApp, mode);
3899}
3900
3901void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3902{
3903 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3904 {
3905 if (check(iter->second))
3906 {
3907 RemoveAura(iter, removeMode);
3908 continue;
3909 }
3910 ++iter;
3911 }
3912}
3913
3914void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3915{
3916 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3917 {
3918 if (check(iter->second))
3919 {
3920 RemoveOwnedAura(iter, removeMode);
3921 continue;
3922 }
3923 ++iter;
3924 }
3925}
3926
3927void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3928{
3929 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3930 {
3931 if (check(iter->second))
3932 {
3933 RemoveAura(iter, removeMode);
3934 iter = m_appliedAuras.lower_bound(spellId);
3935 continue;
3936 }
3937 ++iter;
3938 }
3939}
3940
3941void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3942{
3943 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3944 {
3945 if (check(iter->second))
3946 {
3947 RemoveOwnedAura(iter, removeMode);
3948 iter = m_ownedAuras.lower_bound(spellId);
3949 continue;
3950 }
3951 ++iter;
3952 }
3953}
3954
3955void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3956{
3957 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3958 {
3959 Aura* aura = (*iter)->GetBase();
3961 ASSERT(aurApp);
3962
3963 ++iter;
3964 if (check(aurApp))
3965 {
3966 uint32 removedAuras = m_removedAurasCount;
3967 RemoveAura(aurApp, removeMode);
3968 if (m_removedAurasCount > removedAuras + 1)
3969 iter = m_modAuras[auraType].begin();
3970 }
3971 }
3972}
3973
3974void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3975{
3976 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3977 {
3978 Aura const* aura = iter->second->GetBase();
3979 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3980 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3981 {
3982 RemoveAura(iter, removeMode);
3983 iter = m_appliedAuras.lower_bound(spellId);
3984 }
3985 else
3986 ++iter;
3987 }
3988}
3989
3990void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode, uint16 num)
3991{
3992 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3993 for (AuraMap::iterator iter = range.first; iter != range.second;)
3994 {
3995 Aura* aura = iter->second;
3996 if ((aura->GetType() == UNIT_AURA_TYPE)
3997 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3998 {
3999 aura->ModStackAmount(-num, removeMode);
4000 return;
4001 }
4002 else
4003 ++iter;
4004 }
4005}
4006
4007void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
4008{
4009 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4010 for (AuraMap::iterator iter = range.first; iter != range.second;)
4011 {
4012 Aura* aura = iter->second;
4013 if (aura->GetCasterGUID() == casterGUID)
4014 {
4015 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
4016
4017 // Call OnDispel hook on AuraScript
4018 aura->CallScriptDispel(&dispelInfo);
4019
4022 else
4024
4025 // Call AfterDispel hook on AuraScript
4026 aura->CallScriptAfterDispel(&dispelInfo);
4027
4028 return;
4029 }
4030 else
4031 ++iter;
4032 }
4033}
4034
4035void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges /*= 1*/)
4036{
4037 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4038 for (AuraMap::iterator iter = range.first; iter != range.second;)
4039 {
4040 Aura* aura = iter->second;
4041 if (aura->GetCasterGUID() == casterGUID)
4042 {
4043 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> damage = { };
4044 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> baseDamage = { };
4045 std::bitset<MAX_SPELL_EFFECTS> effMask;
4046 std::bitset<MAX_SPELL_EFFECTS> recalculateMask;
4047 Unit* caster = aura->GetCaster();
4048 for (AuraEffect const* aurEff : aura->GetAuraEffects())
4049 {
4050 SpellEffIndex i = aurEff->GetEffIndex();
4051 baseDamage[i] = aurEff->GetBaseAmount();
4052 damage[i] = aurEff->GetAmount();
4053 effMask[i] = true;
4054 if (aurEff->CanBeRecalculated())
4055 recalculateMask[i] = true;
4056 }
4057
4059 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
4060 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
4061
4062 if (Unit* unitStealer = stealer->ToUnit())
4063 {
4064 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
4065 {
4066 if (stealCharge)
4067 oldAura->ModCharges(stolenCharges);
4068 else
4069 oldAura->ModStackAmount(stolenCharges);
4070 oldAura->SetDuration(int32(dur));
4071 }
4072 else
4073 {
4074 // single target state must be removed before aura creation to preserve existing single target aura
4075 if (aura->IsSingleTarget())
4076 aura->UnregisterSingleTarget();
4077
4078 AuraCreateInfo createInfo(aura->GetCastId(), aura->GetSpellInfo(), aura->GetCastDifficulty(), effMask.to_ulong(), unitStealer);
4079 createInfo
4081 .SetBaseAmount(baseDamage.data())
4082 .SetStackAmount(stolenCharges);
4083
4084 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
4085 {
4086 // created aura must not be single target aura,, so stealer won't loose it on recast
4087 if (newAura->IsSingleTarget())
4088 {
4089 newAura->UnregisterSingleTarget();
4090 // bring back single target aura status to the old aura
4091 aura->SetIsSingleTarget(true);
4092 caster->GetSingleCastAuras().push_front(aura);
4093 }
4094 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
4095 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), recalculateMask.to_ulong(), damage.data());
4096 newAura->ApplyForTargets();
4097 }
4098 }
4099 }
4100
4101 if (stealCharge)
4102 aura->ModCharges(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4103 else
4104 aura->ModStackAmount(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4105
4106 return;
4107 }
4108 else
4109 ++iter;
4110 }
4111}
4112
4114{
4115 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
4116 {
4117 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
4118 {
4119 RemoveAura(iter);
4120 iter = m_appliedAuras.lower_bound(spellId);
4121 }
4122 else
4123 ++iter;
4124 }
4125}
4126
4127void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
4128{
4129 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
4130 {
4131 Aura* aura = (*iter)->GetBase();
4133 ASSERT(aurApp);
4134
4135 ++iter;
4136 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4137 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
4138 {
4139 uint32 removedAuras = m_removedAurasCount;
4140 RemoveAura(aurApp);
4141 if (m_removedAurasCount > removedAuras + 1)
4142 iter = m_modAuras[auraType].begin();
4143 }
4144 }
4145}
4146
4148{
4149 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4150 {
4151 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
4152 if (spell->Attributes & flags)
4153 RemoveAura(iter);
4154 else
4155 ++iter;
4156 }
4157}
4158
4159void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
4160{
4161 // single target auras from other casters
4162 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
4163 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
4164 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
4165 // leading to assertion failures if the aura was cast on a player that can
4166 // (and is changing map at the point where this function is called).
4167 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
4168 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
4169 // to register in m_appliedAuras
4170 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4171 {
4172 Aura const* aura = iter->second;
4173
4174 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
4175 {
4176 if (!onPhaseChange)
4177 RemoveOwnedAura(iter);
4178 else
4179 {
4180 Unit* caster = aura->GetCaster();
4181 if (!caster || !caster->InSamePhase(this))
4182 RemoveOwnedAura(iter);
4183 else
4184 ++iter;
4185 }
4186 }
4187 else
4188 ++iter;
4189 }
4190
4191 // single target auras at other targets
4192 AuraList& scAuras = GetSingleCastAuras();
4193 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4194 {
4195 Aura* aura = *iter;
4196 if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->InSamePhase(this)))
4197 {
4198 aura->Remove();
4199 iter = scAuras.begin();
4200 }
4201 else
4202 ++iter;
4203 }
4204}
4205
4206template<typename InterruptFlag>
4207bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*auraSpellInfo*/, bool /*isChannel*/, SpellInfo const* /*interruptSource*/)
4208{
4209 return false;
4210}
4211
4212template<>
4213bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* auraSpellInfo, bool isChannel, SpellInfo const* interruptSource)
4214{
4215 switch (flag)
4216 {
4218 return unit->CanCastSpellWhileMoving(auraSpellInfo);
4221 if (interruptSource)
4222 {
4223 if (interruptSource->HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED) && auraSpellInfo->Dispel == DISPEL_STEALTH)
4224 return true;
4225
4226 if (interruptSource->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_INVISIBLE) && auraSpellInfo->Dispel == DISPEL_INVISIBILITY)
4227 return true;
4228
4229 if (interruptSource->HasAttribute(SPELL_ATTR9_ALLOW_CAST_WHILE_CHANNELING) && isChannel)
4230 return true;
4231 }
4232 break;
4233 default:
4234 break;
4235 }
4236
4237 return false;
4238}
4239
4240template <typename InterruptFlags>
4241void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source)
4242{
4243 if (!HasInterruptFlag(flag))
4244 return;
4245
4246 // interrupt auras
4247 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4248 {
4249 Aura* aura = (*iter)->GetBase();
4250 ++iter;
4251 if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag)
4252 && (!source || aura->GetId() != source->Id)
4253 && !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo(), false, source))
4254 {
4255 uint32 removedAuras = m_removedAurasCount;
4257 if (m_removedAurasCount > removedAuras + 1)
4258 iter = m_interruptableAuras.begin();
4259 }
4260 }
4261
4262 // interrupt channeled spell
4264 if (spell->getState() == SPELL_STATE_CHANNELING
4265 && spell->GetSpellInfo()->HasChannelInterruptFlag(flag)
4266 && (!source || spell->GetSpellInfo()->Id != source->Id)
4267 && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo(), true, source))
4269
4271}
4272
4275
4276void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID)
4277{
4278 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4279 {
4280 Aura const* aura = iter->second->GetBase();
4281 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4282 {
4283 SpellInfo const* spell = aura->GetSpellInfo();
4284 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4285 {
4286 RemoveAura(iter);
4287 continue;
4288 }
4289 }
4290 ++iter;
4291 }
4292}
4293
4295{
4296 if (withRoot)
4298
4300}
4301
4302void Unit::RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4303{
4304 std::vector<Aura*> aurasToUpdateTargets;
4305 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4306 {
4307 Aura* aura = aurApp->GetBase();
4308 if (exceptSpellId && aura->GetId() == exceptSpellId)
4309 return false;
4310
4311 uint64 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4312 if (!(appliedMechanicMask & mechanicMaskToRemove))
4313 return false;
4314
4315 // spell mechanic matches required mask for removal
4316 if ((UI64LIT(1) << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4317 return true;
4318
4319 // effect mechanic matches required mask for removal - don't remove, only update targets
4320 aurasToUpdateTargets.push_back(aura);
4321 return false;
4322 }, removeMode);
4323
4324 for (Aura* aura : aurasToUpdateTargets)
4325 {
4326 aura->UpdateTargetMap(aura->GetCaster());
4327
4328 // Fully remove the aura if all effects were removed
4329 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4330 aura->Remove(removeMode);
4331 }
4332}
4333
4335{
4336 uint64 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4337 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4338 {
4339 Aura const* aura = iter->second->GetBase();
4340 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4341 {
4342 RemoveAura(iter);
4343 continue;
4344 }
4345 ++iter;
4346 }
4347}
4348
4350{
4351 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4352 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4353 {
4354 Aura* aura = iter->second;
4355 ++iter;
4356 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4357 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4358 {
4359 AuraApplication * aurApp = itr->second;
4360 ++itr;
4361 Unit* target = aurApp->GetTarget();
4362 if (target == this)
4363 continue;
4364 target->RemoveAura(aurApp);
4365 // things linked on aura remove may apply new area aura - so start from the beginning
4366 iter = m_ownedAuras.begin();
4367 }
4368 }
4369
4370 // remove area auras owned by others
4371 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4372 {
4373 if (iter->second->GetBase()->GetOwner() != this)
4374 {
4375 RemoveAura(iter);
4376 }
4377 else
4378 ++iter;
4379 }
4380}
4381
4383{
4384 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4385 // we want to have all auras removed, so use your brain when linking events
4386 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4387 {
4388 AuraApplicationMap::iterator aurAppIter;
4389 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4391
4392 AuraMap::iterator aurIter;
4393 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4394 RemoveOwnedAura(aurIter);
4395
4396 const int maxIteration = 50;
4397 // give this loop a few tries, if there are still auras then log as much information as possible
4398 if (counter >= maxIteration)
4399 {
4400 std::stringstream sstr;
4401 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4402 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4403 sstr << GetDebugInfo() << "\n";
4404
4405 if (!m_appliedAuras.empty())
4406 {
4407 sstr << "m_appliedAuras:" << "\n";
4408
4409 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4410 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4411 }
4412
4413 if (!m_ownedAuras.empty())
4414 {
4415 sstr << "m_ownedAuras:" << "\n";
4416
4417 for (auto const& [spellId, aura] : m_ownedAuras)
4418 sstr << aura->GetDebugInfo() << "\n";
4419 }
4420
4421 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4422 ABORT_MSG("%s", sstr.str().c_str());
4423
4424 break;
4425 }
4426 }
4427}
4428
4430{
4431 // in join, remove positive buffs, on end, remove negative
4432 // used to remove positive visible auras in arenas
4433 RemoveAppliedAuras([](AuraApplication const* aurApp)
4434 {
4435 Aura const* aura = aurApp->GetBase();
4436 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_ALLOW_ENTERING_ARENA) // don't remove stances, shadowform, pally/hunter auras
4437 && !aura->IsPassive() // don't remove passive auras
4438 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD))) || // not negative death persistent auras
4439 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ENTERING_ARENA); // special marker, always remove
4440 });
4441}
4442
4444{
4445 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4446 return;
4447
4448 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4449 // don't remove clone caster on evade (to be verified)
4450 auto evadeAuraCheck = [](Aura const* aura)
4451 {
4452 if (aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
4453 return false;
4454
4455 if (aura->HasEffectType(SPELL_AURA_CLONE_CASTER))
4456 return false;
4457
4458 if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
4459 return false;
4460
4461 return true;
4462 };
4463
4464 auto evadeAuraApplicationCheck = [&evadeAuraCheck](AuraApplication const* aurApp)
4465 {
4466 return evadeAuraCheck(aurApp->GetBase());
4467 };
4468
4469 RemoveAppliedAuras(evadeAuraApplicationCheck);
4470 RemoveOwnedAuras(evadeAuraCheck);
4471}
4472
4474{
4475 // used just after dieing to remove all visible auras
4476 // and disable the mods for the passive ones
4477 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4478 {
4479 Aura const* aura = iter->second->GetBase();
4480 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4482 else
4483 ++iter;
4484 }
4485
4486 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4487 {
4488 Aura* aura = iter->second;
4489 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4491 else
4492 ++iter;
4493 }
4494}
4495
4497{
4498 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4499 {
4500 Aura const* aura = iter->second->GetBase();
4501 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4503 else
4504 ++iter;
4505 }
4506
4507 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4508 {
4509 Aura* aura = iter->second;
4510 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4512 else
4513 ++iter;
4514 }
4515}
4516
4518{
4519 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4520 {
4521 Aura const* aura = iter->second->GetBase();
4522 if (aura->GetSpellInfo()->HasAura(type))
4523 ++iter;
4524 else
4526 }
4527
4528 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4529 {
4530 Aura* aura = iter->second;
4531 if (aura->GetSpellInfo()->HasAura(type))
4532 ++iter;
4533 else
4535 }
4536}
4537
4539{
4540 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4541 {
4542 Aura const* aura = iter->second->GetBase();
4543 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4544 ++iter;
4545 else
4547 }
4548
4549 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4550 {
4551 Aura* aura = iter->second;
4552 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4553 ++iter;
4554 else
4556 }
4557}
4558
4560{
4561 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4562 {
4563 Aura* aura = iter->second;
4564 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4565 {
4566 RemoveOwnedAura(iter);
4567 continue;
4568 }
4569 ++iter;
4570 }
4571}
4572
4573void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4574{
4575 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4576 for (; range.first != range.second; ++range.first)
4577 {
4578 Aura* aura = range.first->second;
4579 if (!caster || aura->GetCasterGUID() == caster)
4580 {
4581 if (aura->GetDuration() < delaytime)
4582 aura->SetDuration(0);
4583 else
4584 aura->SetDuration(aura->GetDuration() - delaytime);
4585
4586 // update for out of range group members (on 1 slot use)
4588 }
4589 }
4590}
4591
4593{
4594 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4595 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4596}
4597
4599{
4600 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4601 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4602}
4603
4604AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4605{
4606 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4607 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4608 {
4609 if (itr->second->HasEffect(effIndex)
4610 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4611 {
4612 return itr->second->GetBase()->GetEffect(effIndex);
4613 }
4614 }
4615 return nullptr;
4616}
4617
4619{
4620 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4621 while (rankSpell)
4622 {
4623 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4624 return aurEff;
4625 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4626 }
4627 return nullptr;
4628}
4629
4630AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID) const
4631{
4632 AuraEffectList const& auras = GetAuraEffectsByType(type);
4633 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4634 {
4635 SpellInfo const* spell = (*i)->GetSpellInfo();
4636 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4637 {
4638 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4639 continue;
4640 return (*i);
4641 }
4642 }
4643 return nullptr;
4644}
4645
4646AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication * except) const
4647{
4648 return GetAuraApplication(spellId, [&](AuraApplication const* app)
4649 {
4650 Aura const* aura = app->GetBase();
4651
4652 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4653 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4654 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4655 && (!except || except != app))
4656 {
4657 return true;
4658 }
4659
4660 return false;
4661 });
4662}
4663
4664AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(AuraApplication const*)> const& predicate) const
4665{
4666 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4667 if (predicate(pair.second))
4668 return pair.second;
4669
4670 return nullptr;
4671}
4672
4673AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4674{
4675 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4676 if (predicate(pair.second->GetBase()))
4677 return pair.second;
4678
4679 return nullptr;
4680}
4681
4682AuraApplication* Unit::GetAuraApplication(std::function<bool(AuraApplication const*)> const& predicate) const
4683{
4684 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4685 if (predicate(pair.second))
4686 return pair.second;
4687
4688 return nullptr;
4689}
4690
4691AuraApplication* Unit::GetAuraApplication(std::function<bool(Aura const*)> const& predicate) const
4692{
4693 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4694 if (predicate(pair.second->GetBase()))
4695 return pair.second;
4696
4697 return nullptr;
4698}
4699
4700Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4701{
4702 AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4703 return aurApp ? aurApp->GetBase() : nullptr;
4704}
4705
4706Aura* Unit::GetAura(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4707{
4708 AuraApplication* aurApp = GetAuraApplication(spellId, predicate);
4709 return aurApp ? aurApp->GetBase() : nullptr;
4710}
4711
4712Aura* Unit::GetAura(std::function<bool(Aura const*)> const& predicate) const
4713{
4714 AuraApplication* aurApp = GetAuraApplication(predicate);
4715 return aurApp ? aurApp->GetBase() : nullptr;
4716}
4717
4718AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication* except) const
4719{
4720 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4721 while (rankSpell)
4722 {
4723 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4724 return aurApp;
4725 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4726 }
4727 return nullptr;
4728}
4729
4730Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4731{
4732 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4733 return aurApp ? aurApp->GetBase() : nullptr;
4734}
4735
4736void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4737{
4738 AuraMap const& auras = GetOwnedAuras();
4739 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4740 {
4741 Aura* aura = itr->second;
4742 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4743 if (!aurApp)
4744 continue;
4745
4746 // don't try to remove passive auras
4747 if (aura->IsPassive())
4748 continue;
4749
4750 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4751 {
4752 // do not remove positive auras if friendly target
4753 // negative auras if non-friendly
4754 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4755 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4756 continue;
4757
4758 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4759 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4760 if (!chance)
4761 continue;
4762
4763 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4764 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4765 // Polymorph instead of 1 / (5 + 1) -> 16%.
4766 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES);
4767 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4768 if (charges > 0)
4769 dispelList.emplace_back(aura, chance, charges);
4770 }
4771 }
4772}
4773
4774bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4775{
4776 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4777 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4778 {
4779 if (itr->second->HasEffect(effIndex)
4780 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4781 {
4782 return true;
4783 }
4784 }
4785 return false;
4786}
4787
4789{
4790 uint32 count = 0;
4791 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4792
4793 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4794 {
4795 if (itr->second->GetBase()->GetStackAmount() == 0)
4796 ++count;
4797 else
4798 count += (uint32)itr->second->GetBase()->GetStackAmount();
4799 }
4800
4801 return count;
4802}
4803
4804bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4805{
4806 return GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask) != nullptr;
4807}
4808
4809bool Unit::HasAura(std::function<bool(Aura const*)> const& predicate) const
4810{
4811 return GetAuraApplication(predicate) != nullptr;
4812}
4813
4814bool Unit::HasAuraType(AuraType auraType) const
4815{
4816 return (!m_modAuras[auraType].empty());
4817}
4818
4820{
4821 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4822 if (caster == eff->GetCasterGUID())
4823 return true;
4824 return false;
4825}
4826
4827bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4828{
4829 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4830 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4831 if (miscvalue == (*i)->GetMiscValue())
4832 return true;
4833 return false;
4834}
4835
4836bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4837{
4838 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4839 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4840 if ((*i)->IsAffectingSpell(affectedSpell))
4841 return true;
4842 return false;
4843}
4844
4845bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4846{
4847 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4848 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4849 if (value == (*i)->GetAmountAsInt())
4850 return true;
4851 return false;
4852}
4853
4854bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4855{
4856 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4857 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4858 return true;
4859 return false;
4860}
4861
4862template <typename InterruptFlags>
4863bool Unit::HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid) const
4864{
4865 if (!HasInterruptFlag(flag))
4866 return false;
4867
4868 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4869 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(flag) &&
4870 (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4871 return true;
4872
4873 return false;
4874}
4875
4878
4879bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
4880{
4881 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4882 {
4883 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4884 if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
4885 return true;
4886
4887 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4888 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4889 if (mechanicMask & (UI64LIT(1) << spellEffectInfo.Mechanic))
4890 return true;
4891 }
4892
4893 return false;
4894}
4895
4896bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster) const
4897{
4898 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
4899 DiminishingLevels level = GetDiminishing(diminishGroup);
4900 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4901 {
4902 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4903 if (spellInfo->GetDiminishingReturnsGroupForSpell() != diminishGroup)
4904 continue;
4905
4906 int32 existingDuration = itr->second->GetBase()->GetDuration();
4907 int32 newDuration = auraSpellInfo->GetMaxDuration();
4908 ApplyDiminishingToDuration(auraSpellInfo, newDuration, caster, level);
4909 if (newDuration > 0 && newDuration < existingDuration)
4910 return true;
4911 }
4912
4913 return false;
4914}
4915
4917{
4919 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4920 {
4921 if ((*i)->GetMiscValue() == script)
4922 if ((*i)->IsAffectingSpell(spell))
4923 return (*i);
4924 }
4925 return nullptr;
4926}
4927
4929{
4930 static const AuraType diseaseAuraTypes[] =
4931 {
4932 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4933 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4934 };
4935
4936 uint32 diseases = 0;
4937 for (AuraType aType : diseaseAuraTypes)
4938 {
4939 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4940 {
4941 // Get auras with disease dispel type by caster
4942 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4943 && (*itr)->GetCasterGUID() == casterGUID)
4944 {
4945 ++diseases;
4946
4947 if (remove)
4948 {
4949 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4950 itr = m_modAuras[aType].begin();
4951 continue;
4952 }
4953 }
4954 ++itr;
4955 }
4956 }
4957 return diseases;
4958}
4959
4961{
4962 static const AuraType diseaseAuraTypes[] =
4963 {
4967 };
4968
4969 uint32 dots = 0;
4970 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4971 {
4972 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4973 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4974 {
4975 // Get auras by caster
4976 if ((*i)->GetCasterGUID() == casterGUID)
4977 ++dots;
4978 }
4979 }
4980 return dots;
4981}
4982
4983float Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4984{
4985 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4986 if (mTotalAuraList.empty())
4987 return 0.0f;
4988
4989 std::map<SpellGroup, SpellEffectValue> sameEffectSpellGroup;
4990 SpellEffectValue modifier = 0;
4991
4992 for (AuraEffect const* aurEff : mTotalAuraList)
4993 {
4994 if (predicate(aurEff))
4995 {
4996 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4997 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4998 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auraType, aurEff->GetAmount(), sameEffectSpellGroup))
4999 modifier += aurEff->GetAmount();
5000 }
5001 }
5002
5003 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
5004 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
5005 modifier += itr->second;
5006
5007 return static_cast<float>(modifier);
5008}
5009
5010float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5011{
5012 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5013 if (mTotalAuraList.empty())
5014 return 1.0f;
5015
5016 std::map<SpellGroup, SpellEffectValue> sameEffectSpellGroup;
5017 SpellEffectValue multiplier = 1.0;
5018
5019 for (AuraEffect const* aurEff : mTotalAuraList)
5020 {
5021 if (predicate(aurEff))
5022 {
5023 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
5024 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
5025 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auraType, aurEff->GetAmount(), sameEffectSpellGroup))
5026 AddPct(multiplier, aurEff->GetAmount());
5027 }
5028 }
5029
5030 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
5031 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
5032 AddPct(multiplier, itr->second);
5033
5034 return static_cast<float>(multiplier);
5035}
5036
5037float Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5038{
5039 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5040 if (mTotalAuraList.empty())
5041 return 0.0f;
5042
5043 SpellEffectValue modifier = 0;
5044 for (AuraEffect const* aurEff : mTotalAuraList)
5045 {
5046 if (predicate(aurEff))
5047 modifier = std::max(modifier, aurEff->GetAmount());
5048 }
5049
5050 return static_cast<float>(modifier);
5051}
5052
5053float Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5054{
5055 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5056 if (mTotalAuraList.empty())
5057 return 0.0f;
5058
5059 SpellEffectValue modifier = 0;
5060 for (AuraEffect const* aurEff : mTotalAuraList)
5061 {
5062 if (predicate(aurEff))
5063 modifier = std::min(modifier, aurEff->GetAmount());
5064 }
5065
5066 return static_cast<float>(modifier);
5067}
5068
5070{
5071 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5072}
5073
5075{
5076 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5077}
5078
5080{
5081 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5082}
5083
5085{
5086 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5087}
5088
5090{
5091 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5092 {
5093 if ((aurEff->GetMiscValue() & miscMask) != 0)
5094 return true;
5095 return false;
5096 });
5097}
5098
5100{
5101 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5102 {
5103 if ((aurEff->GetMiscValue() & miscMask) != 0)
5104 return true;
5105 return false;
5106 });
5107}
5108
5109float Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
5110{
5111 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
5112 {
5113 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
5114 return true;
5115 return false;
5116 });
5117}
5118
5120{
5121 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5122 {
5123 if ((aurEff->GetMiscValue() & miscMask) != 0)
5124 return true;
5125 return false;
5126 });
5127}
5128
5130{
5131 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5132 {
5133 if (aurEff->GetMiscValue() == miscValue)
5134 return true;
5135 return false;
5136 });
5137}
5138
5140{
5141 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5142 {
5143 if (aurEff->GetMiscValue() == miscValue)
5144 return true;
5145 return false;
5146 });
5147}
5148
5150{
5151 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5152 {
5153 if (aurEff->GetMiscValue() == miscValue)
5154 return true;
5155 return false;
5156 });
5157}
5158
5160{
5161 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5162 {
5163 if (aurEff->GetMiscValue() == miscValue)
5164 return true;
5165 return false;
5166 });
5167}
5168
5169float Unit::GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5170{
5171 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5172 {
5173 if (aurEff->IsAffectingSpell(affectedSpell))
5174 return true;
5175 return false;
5176 });
5177}
5178
5179float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5180{
5181 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5182 {
5183 if (aurEff->IsAffectingSpell(affectedSpell))
5184 return true;
5185 return false;
5186 });
5187}
5188
5189float Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5190{
5191 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5192 {
5193 if (aurEff->IsAffectingSpell(affectedSpell))
5194 return true;
5195 return false;
5196 });
5197}
5198
5199float Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5200{
5201 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5202 {
5203 if (aurEff->IsAffectingSpell(affectedSpell))
5204 return true;
5205 return false;
5206 });
5207}
5208
5210{
5211 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
5212 {
5213 m_floatStatPosBuff[i] = 0.0f;
5214 m_floatStatNegBuff[i] = 0.0f;
5216 }
5217}
5218
5220{
5221 float modPos = 0.0f;
5222 float modNeg = 0.0f;
5223 float factor = 0.0f;
5224
5225 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5226
5227 // includes value from items and enchantments
5228 float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
5229 if (modValue > 0.f)
5230 modPos += modValue;
5231 else
5232 modNeg += modValue;
5233
5234 if (IsGuardian())
5235 {
5236 modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
5237 if (modValue > 0.f)
5238 modPos += modValue;
5239 else
5240 modNeg += modValue;
5241 }
5242
5243 // SPELL_AURA_MOD_STAT_BONUS_PCT only affects BASE_VALUE
5244 modPos = CalculatePct(modPos, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5245 modNeg = CalculatePct(modNeg, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5246
5247 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5248 {
5249 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
5250 return true;
5251 return false;
5252 });
5253
5254 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5255 {
5256 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5257 return true;
5258 return false;
5259 });
5260
5261 factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
5262 {
5263 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5264 return true;
5265 return false;
5266 });
5267
5268 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
5269 {
5270 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5271 return true;
5272 return false;
5273 });
5274
5275 modPos *= factor;
5276 modNeg *= factor;
5277
5278 m_floatStatPosBuff[stat] = modPos;
5279 m_floatStatNegBuff[stat] = modNeg;
5280
5282}
5283
5289
5291{
5292 m_dynObj.push_back(dynObj);
5293 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5295}
5296
5298{
5299 std::erase(m_dynObj, dynObj);
5300 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5302}
5303
5305{
5306 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5307 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5308}
5309
5310std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5311{
5312 std::vector<DynamicObject*> dynamicobjects;
5313 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5314 if ((*i)->GetSpellId() == spellId)
5315 dynamicobjects.push_back(*i);
5316
5317 return dynamicobjects;
5318}
5319
5321{
5322 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5323 {
5324 DynamicObject* dynObj = *i;
5325 if (dynObj->GetSpellId() == spellId)
5326 {
5327 dynObj->Remove();
5328 i = m_dynObj.begin();
5329 }
5330 else
5331 ++i;
5332 }
5333}
5334
5336{
5337 while (!m_dynObj.empty())
5338 m_dynObj.back()->Remove();
5339}
5340
5342{
5343 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5344 return gameobjects.empty() ? nullptr : gameobjects.front();
5345}
5346
5347std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5348{
5349 std::vector<GameObject*> gameobjects;
5350 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5351 if ((*i)->GetSpellId() == spellId)
5352 gameobjects.push_back(*i);
5353
5354 return gameobjects;
5355}
5356
5358{
5359 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5360 return;
5361
5362 m_gameObj.push_back(gameObj);
5363 gameObj->SetOwnerGUID(GetGUID());
5364
5365 if (gameObj->GetSpellId())
5366 {
5367 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId(), GetMap()->GetDifficultyID());
5368 // Need disable spell use for owner
5369 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5370 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5371 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5372 }
5373
5375 ToCreature()->AI()->JustSummonedGameobject(gameObj);
5376}
5377
5378void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5379{
5380 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5381 return;
5382
5384
5385 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
5386 {
5387 if (m_ObjectSlot[i] == gameObj->GetGUID())
5388 {
5389 m_ObjectSlot[i].Clear();
5390 break;
5391 }
5392 }
5393
5394 // GO created by some spell
5395 if (uint32 spellid = gameObj->GetSpellId())
5396 {
5397 RemoveAurasDueToSpell(spellid);
5398
5399 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid, GetMap()->GetDifficultyID());
5400 // Need activate spell use for owner
5401 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5402 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5403 GetSpellHistory()->SendCooldownEvent(createBySpell);
5404 }
5405
5406 m_gameObj.remove(gameObj);
5407
5410
5411 if (del)
5412 {
5413 gameObj->SetRespawnTime(0);
5414 gameObj->Delete();
5415 }
5416}
5417
5418void Unit::RemoveGameObject(uint32 spellid, bool del)
5419{
5420 if (m_gameObj.empty())
5421 return;
5422 GameObjectList::iterator i, next;
5423 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
5424 {
5425 next = i;
5426 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5427 {
5428 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5429 if (del)
5430 {
5431 (*i)->SetRespawnTime(0);
5432 (*i)->Delete();
5433 }
5434
5435 next = m_gameObj.erase(i);
5436 }
5437 else
5438 ++next;
5439 }
5440}
5441
5443{
5444 // remove references to unit
5445 while (!m_gameObj.empty())
5446 {
5447 GameObjectList::iterator i = m_gameObj.begin();
5448 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5449 (*i)->SetRespawnTime(0);
5450 (*i)->Delete();
5451 m_gameObj.erase(i);
5452 }
5453}
5454
5456{
5457 m_areaTrigger.push_back(areaTrigger);
5458 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5459 ToCreature()->AI()->JustRegisteredAreaTrigger(areaTrigger);
5460}
5461
5463{
5464 std::erase(m_areaTrigger, areaTrigger);
5465 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5466 ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger);
5467}
5468
5470{
5471 std::vector<AreaTrigger*> areaTriggers = GetAreaTriggers(spellId);
5472 return areaTriggers.empty() ? nullptr : areaTriggers.front();
5473}
5474
5475std::vector<AreaTrigger*> Unit::GetAreaTriggers(uint32 spellId) const
5476{
5477 std::vector<AreaTrigger*> areaTriggers;
5478 for (AreaTriggerList::const_iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end(); ++i)
5479 if ((*i)->GetSpellId() == spellId)
5480 areaTriggers.push_back(*i);
5481
5482 return areaTriggers;
5483}
5484
5486{
5487 for (AreaTriggerList::iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end();)
5488 {
5489 AreaTrigger* areaTrigger = *i;
5490 if (areaTrigger->GetSpellId() == spellId)
5491 {
5492 areaTrigger->Remove();
5493 i = m_areaTrigger.begin();
5494 }
5495 else
5496 ++i;
5497 }
5498}
5499
5501{
5502 for (AreaTrigger* areaTrigger : m_areaTrigger)
5503 {
5504 if (areaTrigger->GetAuraEffect() == aurEff)
5505 {
5506 areaTrigger->Remove();
5507 break; // There can only be one AreaTrigger per AuraEffect
5508 }
5509 }
5510}
5511
5512void Unit::RemoveAllAreaTriggers(AreaTriggerRemoveReason reason /*= AreaTriggerRemoveReason::Default*/)
5513{
5514 for (AreaTrigger* at : AreaTriggerList(std::move(m_areaTrigger)))
5515 {
5516 if (reason == AreaTriggerRemoveReason::UnitDespawn && at->GetTemplate()->ActionSetFlags.HasFlag(AreaTriggerActionSetFlag::DontDespawnWithCreator))
5517 continue;
5518
5519 at->Remove();
5520 }
5521}
5522
5524{
5525 m_insideAreaTriggers.push_back(areaTrigger);
5526}
5527
5529{
5530 std::erase(m_insideAreaTriggers, areaTrigger);
5531}
5532
5534{
5535 AreaTriggerList atList = std::move(m_insideAreaTriggers);
5536 for (AreaTrigger* at : atList)
5537 at->HandleUnitExit(this);
5538}
5539
5541{
5543 packet.Me = log->target->GetGUID();
5544 packet.CasterGUID = log->attacker ? log->attacker->GetGUID() : ObjectGuid::Empty;
5545 packet.CastID = log->castId;
5546 packet.SpellID = log->Spell ? log->Spell->Id : 0;
5547 packet.Visual = log->SpellVisual;
5548 packet.Damage = log->damage;
5549 packet.OriginalDamage = log->originalDamage;
5550 if (log->damage > log->preHitHealth)
5551 packet.Overkill = log->damage - log->preHitHealth;
5552 else
5553 packet.Overkill = -1;
5554
5555 packet.SchoolMask = log->schoolMask;
5556 packet.Absorbed = log->absorb;
5557 packet.Resisted = log->resist;
5558 packet.ShieldBlock = log->blocked;
5560 packet.Periodic = log->periodicLog;
5561 packet.Flags = log->HitInfo;
5562
5564 if (contentTuningParams.GenerateDataForUnits(log->attacker, log->target))
5565 packet.ContentTuning = contentTuningParams;
5566
5567 SendCombatLogMessage(&packet);
5568}
5569
5570/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget,
5571 ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
5572 Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5573{
5574 static constexpr int32 ProcChainHardLimit = 10;
5575 if (spell && spell->GetProcChainLength() >= ProcChainHardLimit)
5576 {
5577 TC_LOG_ERROR("spells.aura.effect", "Unit::ProcSkillsAndAuras: Possible infinite proc loop detected, current triggering spell {}", spell->GetDebugInfo().c_str());
5578 return;
5579 }
5580
5581 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5582 SpellInfo const* spellInfo = [&]() -> SpellInfo const*
5583 {
5584 if (spell)
5585 return spell->GetSpellInfo();
5586 if (damageInfo)
5587 return damageInfo->GetSpellInfo();
5588 if (healInfo)
5589 return healInfo->GetSpellInfo();
5590 return nullptr;
5591 }();
5592 if (typeMaskActor && actor && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)))
5593 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5594
5595 if (typeMaskActionTarget && actionTarget && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)))
5596 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5597
5598 if (actor)
5599 actor->TriggerAurasProcOnEvent(nullptr, nullptr, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5600}
5601
5603{
5604 AuraEffect const* aura = info->auraEff;
5606 data.TargetGUID = GetGUID();
5607 data.CasterGUID = aura->GetCasterGUID();
5608 data.SpellID = aura->GetId();
5609 data.LogData.Initialize(this);
5610
5611 WorldPackets::CombatLog::PeriodicAuraLogEffect& spellLogEffect = data.Effects.emplace_back();
5612 spellLogEffect.Effect = aura->GetAuraType();
5613 spellLogEffect.Amount = info->damage;
5614 spellLogEffect.OriginalDamage = info->originalDamage;
5615 spellLogEffect.OverHealOrKill = info->overDamage;
5616 spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask();
5617 spellLogEffect.AbsorbedOrAmplitude = info->absorb;
5618 spellLogEffect.Resisted = info->resist;
5619 spellLogEffect.Crit = info->critical;
5621
5623 if (Unit* caster = ObjectAccessor::GetUnit(*this, aura->GetCasterGUID()))
5624 if (contentTuningParams.GenerateDataForUnits(caster, this))
5625 spellLogEffect.ContentTuning = contentTuningParams;
5626
5627 SendCombatLogMessage(&data);
5628}
5629
5631{
5633 procResist.Caster = GetGUID();
5634 procResist.SpellID = spellId;
5635 procResist.Target = target->GetGUID();
5636 SendMessageToSet(procResist.Write(), true);
5637}
5638
5639void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId, bool isPeriodic)
5640{
5642 spellOrDamageImmune.CasterGUID = GetGUID();
5643 spellOrDamageImmune.VictimGUID = target->GetGUID();
5644 spellOrDamageImmune.SpellID = spellId;
5645 spellOrDamageImmune.IsPeriodic = isPeriodic;
5646 SendMessageToSet(spellOrDamageImmune.Write(), true);
5647}
5648
5650{
5652 packet.Flags = damageInfo->HitInfo;
5653 packet.AttackerGUID = damageInfo->Attacker->GetGUID();
5654 packet.VictimGUID = damageInfo->Target->GetGUID();
5655 packet.Damage = damageInfo->Damage;
5656 packet.OriginalDamage = damageInfo->OriginalDamage;
5657 int32 overkill = damageInfo->Damage - damageInfo->Target->GetHealth();
5658 packet.OverDamage = (overkill < 0 ? -1 : overkill);
5659
5660 packet.SubDmg.emplace();
5661 packet.SubDmg->SchoolMask = damageInfo->DamageSchoolMask; // School of sub damage
5662 packet.SubDmg->FDamage = damageInfo->Damage; // sub damage
5663 packet.SubDmg->Damage = damageInfo->Damage; // Sub Damage
5664 packet.SubDmg->Absorbed = damageInfo->Absorb;
5665 packet.SubDmg->Resisted = damageInfo->Resist;
5666
5667 packet.VictimState = damageInfo->TargetState;
5668 packet.BlockAmount = damageInfo->Blocked;
5669 packet.RageGained = damageInfo->RageGained;
5670
5671 packet.LogData.Initialize(damageInfo->Attacker);
5672
5674 if (contentTuningParams.GenerateDataForUnits(damageInfo->Attacker, damageInfo->Target))
5675 packet.ContentTuning = contentTuningParams;
5676
5677 SendCombatLogMessage(&packet);
5678}
5679
5680void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount, uint32 RageGained)
5681{
5682 CalcDamageInfo dmgInfo;
5683 dmgInfo.HitInfo = HitInfo;
5684 dmgInfo.Attacker = this;
5685 dmgInfo.Target = target;
5686 dmgInfo.Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5687 dmgInfo.OriginalDamage = Damage;
5688 dmgInfo.DamageSchoolMask = damageSchoolMask;
5689 dmgInfo.Absorb = AbsorbDamage;
5690 dmgInfo.Resist = Resist;
5691 dmgInfo.TargetState = TargetState;
5692 dmgInfo.Blocked = BlockedAmount;
5693 dmgInfo.RageGained = RageGained;
5694 SendAttackStateUpdate(&dmgInfo);
5695}
5696
5697void Unit::SetPowerType(Powers power, bool sendUpdate/* = true*/, bool onInit /*= false*/)
5698{
5699 if (!onInit && GetPowerType() == power)
5700 return;
5701
5702 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(power);
5703 if (!powerTypeEntry)
5704 return;
5705
5706 if (IsCreature() && !powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::IsUsedByNPCs))
5707 return;
5708
5710
5711 // Update max power
5712 UpdateMaxPower(power);
5713
5714 // Update current power
5715 if (!onInit)
5716 {
5717 switch (power)
5718 {
5719 case POWER_MANA: // Keep the same (druid form switching...)
5720 case POWER_ENERGY:
5721 break;
5722 case POWER_RAGE: // Reset to zero
5723 SetPower(POWER_RAGE, 0);
5724 break;
5725 case POWER_FOCUS: // Make it full
5726 SetFullPower(power);
5727 break;
5728 default:
5729 break;
5730 }
5731 }
5732 else
5733 SetInitialPowerValue(power);
5734
5735 if (!sendUpdate)
5736 return;
5737
5738 if (Player* thisPlayer = ToPlayer())
5739 {
5740 if (thisPlayer->GetGroup())
5741 thisPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
5742 }
5743 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
5744 {
5745 if (pet->isControlled())
5746 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
5747 }*/
5748}
5749
5751{
5752 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType);
5753 if (!powerTypeEntry)
5754 return;
5755
5756 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UnitsUseDefaultPowerOnInit))
5757 SetPower(powerType, powerTypeEntry->DefaultPower);
5758 else
5759 SetFullPower(powerType);
5760}
5761
5763{
5764 Powers displayPower = POWER_MANA;
5765 switch (GetShapeshiftForm())
5766 {
5767 case FORM_GHOUL:
5768 case FORM_CAT_FORM:
5769 displayPower = POWER_ENERGY;
5770 break;
5771 case FORM_BEAR_FORM:
5773 displayPower = POWER_RAGE;
5774 break;
5775 case FORM_TRAVEL_FORM:
5776 case FORM_GHOST_WOLF:
5777 displayPower = POWER_MANA;
5778 break;
5779 default:
5780 {
5782 if (!powerTypeAuras.empty())
5783 {
5784 AuraEffect const* powerTypeAura = powerTypeAuras.front();
5785 displayPower = Powers(powerTypeAura->GetMiscValue());
5786 }
5787 else
5788 {
5789 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5790 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5791 displayPower = Powers(cEntry->DisplayPower);
5792
5793 if (Vehicle* vehicle = GetVehicleKit())
5794 {
5795 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID[0]))
5796 displayPower = Powers(powerDisplay->ActualType);
5797 }
5798 else if (IsHunterPet())
5799 displayPower = POWER_FOCUS;
5800 }
5801 break;
5802 }
5803 }
5804
5805 return displayPower;
5806}
5807
5812
5819
5820void Unit::_addAttacker(Unit* pAttacker)
5821{
5822 m_attackers.insert(pAttacker);
5823}
5824
5826{
5827 m_attackers.erase(pAttacker);
5828}
5829
5830Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5831{
5832 if (!IsEngaged())
5833 return nullptr;
5834
5835 if (Unit* victim = GetVictim())
5836 if ((!IsPet() && !GetPlayerMovingMe()) || IsInCombatWith(victim))
5837 return victim;
5838
5839 CombatManager const& mgr = GetCombatManager();
5840 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5841 Unit* owner = GetCharmerOrOwner();
5842 if (mgr.HasPvPCombat())
5843 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5844 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5845 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5846 if (mgr.HasPvECombat())
5847 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5848 if (owner && (owner->GetCombatManager().HasPvECombat()))
5849 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5850 return nullptr;
5851}
5852
5853bool Unit::Attack(Unit* victim, bool meleeAttack)
5854{
5855 if (!victim || victim == this)
5856 return false;
5857
5858 // dead units can neither attack nor be attacked
5859 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5860 return false;
5861
5862 // player cannot attack in mount state
5863 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5864 return false;
5865
5866 Creature* creature = ToCreature();
5867 // creatures cannot attack while evading
5868 if (creature && creature->IsInEvadeMode())
5869 return false;
5870
5871 // nobody can attack GM in GM-mode
5872 if (victim->GetTypeId() == TYPEID_PLAYER)
5873 {
5874 if (victim->ToPlayer()->IsGameMaster())
5875 return false;
5876 }
5877 else
5878 {
5879 if (victim->ToCreature()->IsEvadingAttacks())
5880 return false;
5881 }
5882
5883 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5886
5887 if (m_attacking)
5888 {
5889 if (m_attacking == victim)
5890 {
5891 // switch to melee attack from ranged/magic
5892 if (meleeAttack)
5893 {
5895 {
5897 SendMeleeAttackStart(victim);
5898 return true;
5899 }
5900 }
5902 {
5904 SendMeleeAttackStop(victim);
5905 return true;
5906 }
5907 return false;
5908 }
5909
5910 // switch target
5912 if (!meleeAttack)
5914 }
5915
5916 if (m_attacking)
5918
5919 m_attacking = victim;
5922
5923 // Set our target
5924 SetTarget(victim->GetGUID());
5925
5926 if (meleeAttack)
5928
5929 // set position before any AI calls/assistance
5930 //if (GetTypeId() == TYPEID_UNIT)
5931 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5932
5933 if (creature && !IsControlledByPlayer())
5934 {
5935 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5936
5938 creature->CallAssistance();
5939
5940 // Remove emote and stand state - will be restored on creature reset
5943 }
5944
5945 // delay offhand weapon attack by 50% of the base attack time
5948
5949 if (meleeAttack)
5950 SendMeleeAttackStart(victim);
5951
5952 // Let the pet know we've started attacking someting. Handles melee attacks only
5953 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5954 if (GetTypeId() == TYPEID_PLAYER)
5955 {
5956 for (Unit* controlled : m_Controlled)
5957 if (Creature* cControlled = controlled->ToCreature())
5958 if (CreatureAI* controlledAI = cControlled->AI())
5959 controlledAI->OwnerAttacked(victim);
5960 }
5961
5962 return true;
5963}
5964
5966{
5967 if (!m_attacking)
5968 return false;
5969
5970 Unit* victim = m_attacking;
5971
5972 m_updateFlag.CombatVictim = false;
5974 m_attacking = nullptr;
5975
5976 // Clear our target
5978
5980
5982
5983 // reset only at real combat stop
5984 if (Creature* creature = ToCreature())
5985 {
5986 creature->SetNoCallAssistance(false);
5987 }
5988
5989 SendMeleeAttackStop(victim);
5990
5991 return true;
5992}
5993
5995{
5996 // iterate attackers
5997 UnitVector toRemove;
5998 AttackerSet const& attackers = getAttackers();
5999 for (Unit* attacker : attackers)
6000 if (!attacker->IsValidAttackTarget(this))
6001 toRemove.push_back(attacker);
6002
6003 for (Unit* attacker : toRemove)
6004 attacker->AttackStop();
6005
6006 // remove our own victim
6007 if (Unit* victim = GetVictim())
6008 if (!IsValidAttackTarget(victim))
6009 AttackStop();
6010}
6011
6012void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
6013{
6014 if (includingCast && IsNonMeleeSpellCast(false))
6016
6017 AttackStop();
6018 if (!unitFilter)
6020 else
6021 {
6022 std::vector<Unit*> attackersToRemove;
6023 attackersToRemove.reserve(m_attackers.size());
6024 std::copy_if(m_attackers.begin(), m_attackers.end(), std::back_inserter(attackersToRemove), unitFilter);
6025
6026 for (Unit* attacker : attackersToRemove)
6027 attacker->AttackStop();
6028 }
6029
6030 if (GetTypeId() == TYPEID_PLAYER)
6031 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6032
6033 m_combatManager.EndAllPvECombat(unitFilter);
6034 if (mutualPvP)
6035 m_combatManager.EndAllPvPCombat(unitFilter);
6036 else // vanish and brethren are weird
6038}
6039
6040void Unit::CombatStopWithPets(bool includingCast)
6041{
6042 CombatStop(includingCast);
6043
6044 for (Unit* minion : m_Controlled)
6045 minion->CombatStop(includingCast);
6046}
6047
6049{
6051 return true;
6052
6053 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6054 if ((*itr)->isAttackingPlayer())
6055 return true;
6056
6057 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6058 if (!m_SummonSlot[i].IsEmpty())
6059 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
6060 if (summon->isAttackingPlayer())
6061 return true;
6062
6063 return false;
6064}
6065
6067{
6068 while (!m_attackers.empty())
6069 {
6070 AttackerSet::iterator iter = m_attackers.begin();
6071 if (!(*iter)->AttackStop())
6072 {
6073 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
6074 m_attackers.erase(iter);
6075 }
6076 }
6077}
6078
6080{
6081 uint32 mask = 1 << (flag - 1);
6082 if (apply)
6083 {
6084 if (!(*m_unitData->AuraState & mask))
6085 {
6087 if (GetTypeId() == TYPEID_PLAYER)
6088 {
6089 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
6090 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
6091 {
6092 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
6093 continue;
6094 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6095 if (!spellInfo || !spellInfo->IsPassive())
6096 continue;
6097 if (spellInfo->CasterAuraState == uint32(flag))
6098 CastSpell(this, itr->first, true);
6099 }
6100 }
6101 else if (Pet* pet = ToCreature()->ToPet())
6102 {
6103 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
6104 {
6105 if (itr->second.state == PETSPELL_REMOVED)
6106 continue;
6107 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6108 if (!spellInfo || !spellInfo->IsPassive())
6109 continue;
6110 if (spellInfo->CasterAuraState == uint32(flag))
6111 CastSpell(this, itr->first, true);
6112 }
6113 }
6114 }
6115 }
6116 else
6117 {
6118 if (*m_unitData->AuraState & mask)
6119 {
6121
6123 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
6124 {
6125 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
6126 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGED))
6127 RemoveAura(itr);
6128 else
6129 ++itr;
6130 }
6131 }
6132 }
6133}
6134
6136{
6137 uint32 auraStates = *m_unitData->AuraState & ~(PER_CASTER_AURA_STATE_MASK);
6138 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
6139 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
6140 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
6141 auraStates |= (1 << (itr->first - 1));
6142
6143 return auraStates;
6144}
6145
6146bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
6147{
6148 if (Caster)
6149 {
6150 if (spellProto)
6151 {
6152 if (Caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_IGNORE_AURASTATE, spellProto))
6153 return true;
6154 }
6155
6156 // Check per caster aura state
6157 // If aura with aurastate by caster not found return false
6158 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
6159 {
6160 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
6161 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
6162 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
6163 return true;
6164 return false;
6165 }
6166 }
6167
6168 return (*m_unitData->AuraState & (1 << (flag - 1))) != 0;
6169}
6170
6172{
6173 if (GetOwnerGUID() == owner)
6174 return;
6175
6177 if (!owner)
6178 return;
6179
6180 // Update owner dependent fields
6181 Player* player = ObjectAccessor::GetPlayer(*this, owner);
6182 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
6183 return;
6184
6185 UpdateData udata(GetMapId());
6186 WorldPacket packet;
6188 udata.BuildPacket(&packet);
6189 player->SendDirectMessage(&packet);
6190}
6191
6193{
6195}
6196
6201
6203{
6205 if (!guid.IsEmpty())
6206 {
6207 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
6208 return master->GetControllingPlayer();
6209 return nullptr;
6210 }
6211 else
6212 return const_cast<Player*>(ToPlayer());
6213}
6214
6216{
6217 ObjectGuid pet_guid = GetMinionGUID();
6218 if (!pet_guid.IsEmpty())
6219 {
6220 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6221 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
6222 return (Minion*)pet;
6223
6224 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
6225 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
6226 }
6227
6228 return nullptr;
6229}
6230
6232{
6233 ObjectGuid pet_guid = GetPetGUID();
6234 if (!pet_guid.IsEmpty())
6235 {
6236 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6237 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6238 return (Guardian*)pet;
6239
6240 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
6241 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
6242 }
6243
6244 return nullptr;
6245}
6246
6247void Unit::SetMinion(Minion *minion, bool apply)
6248{
6249 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
6250
6251 if (apply)
6252 {
6253 if (!minion->GetOwnerGUID().IsEmpty())
6254 {
6255 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6256 return;
6257 }
6258
6259 if (!IsInWorld())
6260 {
6261 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
6262 return;
6263 }
6264
6265 minion->SetOwnerGUID(GetGUID());
6266
6267 m_Controlled.insert(minion);
6268
6269 if (GetTypeId() == TYPEID_PLAYER)
6270 {
6271 minion->m_ControlledByPlayer = true;
6273 }
6274
6275 // Can only have one pet. If a new one is summoned, dismiss the old one.
6276 if (minion->IsGuardianPet())
6277 {
6278 if (Guardian* oldPet = GetGuardianPet())
6279 {
6280 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
6281 {
6282 // remove existing minion pet
6283 if (Pet* oldPetAsPet = oldPet->ToPet())
6284 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
6285 else
6286 oldPet->UnSummon();
6287 SetPetGUID(minion->GetGUID());
6289 }
6290 }
6291 else
6292 {
6293 SetPetGUID(minion->GetGUID());
6295 }
6296 }
6297
6299 {
6300 if (GetMinionGUID().IsEmpty())
6301 SetMinionGUID(minion->GetGUID());
6302 }
6303
6304 SummonPropertiesEntry const* properties = minion->m_Properties;
6305 if (properties && SummonTitle(properties->Title) == SummonTitle::Companion)
6306 {
6307 SetCritterGUID(minion->GetGUID());
6308 if (Player const* thisPlayer = ToPlayer())
6309 {
6311 {
6312 if (BattlePets::BattlePet const* pet = thisPlayer->GetSession()->GetBattlePetMgr()->GetPet(thisPlayer->GetSummonedBattlePetGUID()))
6313 {
6314 minion->SetBattlePetCompanionGUID(thisPlayer->GetSummonedBattlePetGUID());
6315 minion->SetBattlePetCompanionNameTimestamp(pet->NameTimestamp);
6316 minion->SetWildBattlePetLevel(pet->PacketInfo.Level);
6317
6318 if (uint32 display = pet->PacketInfo.DisplayID)
6319 minion->SetDisplayId(display, true);
6320 }
6321 }
6322 }
6323 }
6324
6325 // PvP, FFAPvP
6327
6328 // FIXME: hack, speed must be set only at follow
6329 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
6330 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
6331 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
6332
6333 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
6334 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6335
6336 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6337 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
6338 }
6339 else
6340 {
6341 if (minion->GetOwnerGUID() != GetGUID())
6342 {
6343 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6344 return;
6345 }
6346
6347 m_Controlled.erase(minion);
6348
6350 if (GetCritterGUID() == minion->GetGUID())
6352
6353 if (minion->IsGuardianPet())
6354 {
6355 if (GetPetGUID() == minion->GetGUID())
6357 }
6358 else if (minion->IsTotem())
6359 {
6360 // All summoned by totem minions must disappear when it is removed.
6361 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell(), DIFFICULTY_NONE))
6362 {
6363 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
6364 {
6365 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
6366 continue;
6367
6368 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
6369 }
6370 }
6371 }
6372
6373 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6374 // Remove infinity cooldown
6375 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6376 GetSpellHistory()->SendCooldownEvent(spellInfo);
6377
6378 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6379 {
6380 if (GetMinionGUID() == minion->GetGUID())
6381 {
6383 // Check if there is another minion
6384 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6385 {
6386 // do not use this check, creature do not have charm guid
6387 //if (GetCharmedGUID() == (*itr)->GetGUID())
6388 if (GetGUID() == (*itr)->GetCharmerGUID())
6389 continue;
6390
6391 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
6392 if ((*itr)->GetOwnerGUID() != GetGUID())
6393 {
6394 OutDebugInfo();
6395 (*itr)->OutDebugInfo();
6396 ABORT();
6397 }
6398 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
6399
6400 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
6401 continue;
6402
6403 SetMinionGUID((*itr)->GetGUID());
6404 // show another pet bar if there is no charm bar
6405 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
6406 {
6407 if ((*itr)->IsPet())
6409 else
6411 }
6412 break;
6413 }
6414 }
6415 }
6416 }
6418}
6419
6420void Unit::GetAllMinionsByEntry(std::list<TempSummon*>& Minions, uint32 entry)
6421{
6422 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6423 {
6424 Unit* unit = *itr;
6425 if (unit->GetEntry() == entry && unit->IsSummon()) // minion, actually
6426 Minions.push_back(unit->ToTempSummon());
6427 }
6428}
6429
6431{
6432 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6433 {
6434 Unit* unit = *itr;
6435 ++itr;
6436 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6437 && unit->ToCreature()->IsSummon()) // minion, actually
6438 unit->ToTempSummon()->UnSummon();
6439 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6440 }
6441}
6442
6443void Unit::SetCharm(Unit* charm, bool apply)
6444{
6445 if (apply)
6446 {
6447 if (GetTypeId() == TYPEID_PLAYER)
6448 {
6449 ASSERT(GetCharmedGUID().IsEmpty(),
6450 "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());
6452 m_charmed = charm;
6453
6454 charm->m_ControlledByPlayer = true;
6457 }
6458 else
6459 charm->m_ControlledByPlayer = false;
6460
6461 // PvP, FFAPvP
6463
6464 ASSERT(charm->GetCharmerGUID().IsEmpty(),
6465 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6467 charm->m_charmer = this;
6468
6471 charm->SetWalk(false);
6472
6473 m_Controlled.insert(charm);
6474 }
6475 else
6476 {
6478
6479 if (GetTypeId() == TYPEID_PLAYER)
6480 {
6481 ASSERT(GetCharmedGUID() == charm->GetGUID(),
6482 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6484 m_charmed = nullptr;
6485 }
6486
6487 ASSERT(charm->GetCharmerGUID() == GetGUID(),
6488 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6490 charm->m_charmer = nullptr;
6491
6492 if (charm->GetTypeId() == TYPEID_PLAYER)
6493 {
6494 charm->m_ControlledByPlayer = true;
6496 charm->ToPlayer()->UpdatePvPState();
6497 }
6498 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6499 {
6500 charm->m_ControlledByPlayer = true;
6502 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6503 }
6504 else
6505 {
6506 charm->m_ControlledByPlayer = false;
6509 }
6510
6511 if (charm->IsWalking() != _isWalkingBeforeCharm)
6513
6514 if (charm->GetTypeId() == TYPEID_PLAYER
6516 || charm->GetOwnerGUID() != GetGUID())
6517 {
6518 m_Controlled.erase(charm);
6519 }
6520 }
6522}
6523
6524/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6525{
6526 int32 gain = 0;
6527 Unit* healer = healInfo.GetHealer();
6528 Unit* victim = healInfo.GetTarget();
6529 uint32 addhealth = healInfo.GetHeal();
6530
6531 if (UnitAI* victimAI = victim->GetAI())
6532 victimAI->HealReceived(healer, addhealth);
6533
6534 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6535 healerAI->HealDone(victim, addhealth);
6536
6537 if (addhealth)
6538 gain = victim->ModifyHealth(int32(addhealth));
6539
6540 // Hook for OnHeal Event
6541 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6542
6543 Unit* unit = healer;
6544 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6545 unit = healer->GetOwner();
6546
6547 if (unit)
6548 {
6549 if (Player* player = unit->ToPlayer())
6550 {
6552 if (Battleground* bg = player->GetBattleground())
6553 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6554
6555 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6556 if (gain)
6557 player->UpdateCriteria(CriteriaType::HealingDone, gain, 0, 0, victim);
6558
6559 player->UpdateCriteria(CriteriaType::HighestHealCast, addhealth);
6560 }
6561 }
6562
6563 if (Player* player = victim->ToPlayer())
6564 {
6565 player->UpdateCriteria(CriteriaType::TotalHealReceived, gain);
6566 player->UpdateCriteria(CriteriaType::HighestHealReceived, addhealth);
6567 }
6568
6569 if (gain)
6570 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6571}
6572
6573bool Unit::IsMagnet() const
6574{
6575 // Grounding Totem
6576 if (*m_unitData->CreatedBySpell == 8177)
6577 return true;
6578
6579 return false;
6580}
6581
6582Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo /*= nullptr*/)
6583{
6585 for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i)
6586 {
6587 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6588 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6589 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6590 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6591 {
6592 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6593 return magnet;
6594 }
6595 }
6596 return victim;
6597}
6598
6600{
6601 // Sequence: charmed, pet, other guardians
6602 Unit* unit = GetCharmed();
6603 if (!unit)
6604 {
6605 ObjectGuid guid = GetMinionGUID();
6606 if (!guid.IsEmpty())
6607 unit = ObjectAccessor::GetUnit(*this, guid);
6608 }
6609
6610 return unit;
6611}
6612
6614{
6615 // possessed pet and vehicle
6616 if (GetTypeId() == TYPEID_PLAYER)
6618
6619 while (!m_Controlled.empty())
6620 {
6621 Unit* target = *m_Controlled.begin();
6622 m_Controlled.erase(m_Controlled.begin());
6623 if (target->GetCharmerGUID() == GetGUID())
6624 target->RemoveCharmAuras();
6625 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6626 target->ToTempSummon()->UnSummon();
6627 else
6628 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6629 }
6630 if (!GetPetGUID().IsEmpty())
6631 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6632 if (!GetMinionGUID().IsEmpty())
6633 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6634 if (!GetCharmedGUID().IsEmpty())
6635 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6636 if (!IsPet()) // pets don't use the flag for this
6637 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6638}
6639
6644
6646{
6647 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6648}
6649
6651{
6652 if (Unit* u = GetCharmed())
6653 return u->isPossessed();
6654 else
6655 return false;
6656}
6657
6659{
6660 Player* player = nullptr;
6661 if (GetTypeId() == TYPEID_PLAYER)
6662 player = ToPlayer();
6663 // Should we enable this also for charmed units?
6664 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6665 player = GetOwner()->ToPlayer();
6666
6667 if (!player)
6668 return nullptr;
6669 Group* group = player->GetGroup();
6670 // When there is no group check pet presence
6671 if (!group)
6672 {
6673 // We are pet now, return owner
6674 if (player != this)
6675 return IsWithinDistInMap(player, radius) ? player : nullptr;
6676 Unit* pet = GetGuardianPet();
6677 // No pet, no group, nothing to return
6678 if (!pet)
6679 return nullptr;
6680 // We are owner now, return pet
6681 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6682 }
6683
6684 std::vector<Unit*> nearMembers;
6685 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6686 nearMembers.reserve(group->GetMembersCount() * 2);
6687
6688 for (GroupReference const& itr : group->GetMembers())
6689 {
6690 Player* Target = itr.GetSource();
6691 // IsHostileTo check duel and controlled by enemy
6692 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6693 nearMembers.push_back(Target);
6694
6695 // Push player's pet to vector
6696 if (Unit* pet = Target->GetGuardianPet())
6697 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6698 nearMembers.push_back(pet);
6699 }
6700
6701 if (nearMembers.empty())
6702 return nullptr;
6703
6704 uint32 randTarget = urand(0, nearMembers.size()-1);
6705 return nearMembers[randTarget];
6706}
6707
6708// only called in Player::SetSeer
6709// so move it to Player?
6711{
6712 if (m_sharedVision.empty())
6713 {
6714 setActive(true);
6716 }
6717 m_sharedVision.push_back(player);
6718}
6719
6720// only called in Player::SetSeer
6722{
6723 m_sharedVision.remove(player);
6724 if (m_sharedVision.empty())
6725 {
6726 setActive(false);
6728 }
6729}
6730
6735
6743
6745{
6746 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6747 {
6748 if (!m_SummonSlot[i])
6749 continue;
6750
6751 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6752 if (OldTotem->IsSummon())
6753 OldTotem->ToTempSummon()->UnSummon();
6754 }
6755}
6756
6757void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6758{
6760
6761 TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: {} Caster: {} Target: {} (Health: {} OverHeal: {} Absorbed: {} Crit: {})", healInfo.GetSpellInfo()->Id, healInfo.GetHealer()->GetGUID().ToString(), healInfo.GetTarget()->GetGUID().ToString(),
6762 healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), critical);
6763
6764 spellHealLog.TargetGUID = healInfo.GetTarget()->GetGUID();
6765 spellHealLog.CasterGUID = healInfo.GetHealer()->GetGUID();
6766 spellHealLog.SpellID = healInfo.GetSpellInfo()->Id;
6767 spellHealLog.Health = healInfo.GetHeal();
6768 spellHealLog.OriginalHeal = healInfo.GetOriginalHeal();
6769 spellHealLog.OverHeal = int32(healInfo.GetHeal()) - healInfo.GetEffectiveHeal();
6770 spellHealLog.Absorbed = healInfo.GetAbsorb();
6771 spellHealLog.Crit = critical;
6772 spellHealLog.LogData.Initialize(healInfo.GetTarget());
6773 SendCombatLogMessage(&spellHealLog);
6774}
6775
6776int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6777{
6778 // calculate heal absorb and reduce healing
6779 Unit::CalcHealAbsorb(healInfo);
6780 Unit::DealHeal(healInfo);
6781 SendHealSpellLog(healInfo, critical);
6782 return healInfo.GetEffectiveHeal();
6783}
6784
6785void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype)
6786{
6788 data.CasterGUID = GetGUID();
6789 data.TargetGUID = victim->GetGUID();
6790 data.SpellID = spellID;
6791 data.Type = powertype;
6792 data.Amount = damage;
6793 data.OverEnergize = overEnergize;
6794 data.LogData.Initialize(victim);
6795 SendCombatLogMessage(&data);
6796}
6797
6798void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6799{
6800 if (Player* player = victim->ToPlayer())
6801 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType))
6802 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UseRegenInterrupt))
6803 player->InterruptPowerRegen(powerType);
6804
6805 int32 gain = victim->ModifyPower(powerType, damage, false);
6806 int32 overEnergize = damage - gain;
6807 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage) / 2, spellInfo, true);
6808 SendEnergizeSpellLog(victim, spellInfo->Id, gain, overEnergize, powerType);
6809}
6810
6811int32 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
6812{
6813 if (!spellProto || !victim)
6814 return pdamage;
6815
6816 int32 DoneTotal = 0;
6817 float DoneTotalMod = 1.0f;
6818
6819 auto callDamageScript = [&](int32& dmg, int32& flatMod, float& pctMod)
6820 {
6821 if (spell)
6822 spell->CallScriptCalcDamageHandlers(spellEffectInfo, victim, dmg, flatMod, pctMod);
6823 else if (aurEff)
6824 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, dmg, flatMod, pctMod);
6825 };
6826
6827 // Some spells don't benefit from done mods
6828 if (damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
6829 {
6830 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6831 return int32(std::max(float(pdamage + DoneTotal) * DoneTotalMod, 0.0f));
6832 }
6833
6834 // For totems get damage bonus from owner
6835 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6836 if (Unit* owner = GetOwner())
6837 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
6838
6839 DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6840
6841 // Done fixed damage bonus auras
6842 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6843 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6844 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6845
6846 // Pets just add their bonus damage to their spell damage
6847 // note that their spell damage is just gain of their own auras
6849 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6850
6851 // Check for table values
6852 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
6853 {
6854 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
6855 if (Player* modOwner = GetSpellModOwner())
6856 {
6857 attackPowerCoeff *= 100.0f;
6858 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
6859 attackPowerCoeff /= 100.0f;
6860 }
6861
6862 WeaponAttackType const attType = [&]()
6863 {
6864 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
6865 return RANGED_ATTACK;
6866
6868 return OFF_ATTACK;
6869
6870 return BASE_ATTACK;
6871 }();
6873 attackPowerBonus += GetTotalAttackPowerValue(attType);
6874 DoneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
6875 }
6876
6877 // Default calculation
6878 if (DoneAdvertisedBenefit)
6879 {
6880 float coeff = spellEffectInfo.BonusCoefficient;
6881 if (Player* modOwner = GetSpellModOwner())
6882 {
6883 coeff *= 100.0f;
6884 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
6885 coeff /= 100.0f;
6886 }
6887
6888 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
6889 }
6890
6891 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6892
6893 float tmpDamage = float(pdamage + DoneTotal) * DoneTotalMod;
6894
6895 // apply spellmod to Done damage (flat and pct)
6896 if (Player* modOwner = GetSpellModOwner())
6897 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage);
6898
6899 return int32(std::max(tmpDamage, 0.0f));
6900}
6901
6902float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const
6903{
6904 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6905 return 1.0f;
6906
6907 // Some spells don't benefit from done mods
6909 return 1.0f;
6910
6911 // Some spells don't benefit from pct done mods
6913 return 1.0f;
6914
6915 // For totems get damage bonus from owner
6916 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6917 if (Unit* owner = GetOwner())
6918 return owner->SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6919
6920 // Done total percent damage auras
6921 float DoneTotalMod = 1.0f;
6922
6923 // Pet damage?
6924 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6925 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->Classification);
6926
6927 // Versatility
6928 if (Player* modOwner = GetSpellModOwner())
6929 AddPct(DoneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
6930
6931 float maxModDamagePercentSchool = 0.0f;
6932 if (Player const* thisPlayer = ToPlayer())
6933 {
6934 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6935 if (spellProto->GetSchoolMask() & (1 << i))
6936 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
6937 }
6938 else
6939 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6940
6941 DoneTotalMod *= maxModDamagePercentSchool;
6942
6943 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6944
6946
6947 // bonus against aurastate
6948 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6949 {
6950 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6951 return true;
6952 return false;
6953 });
6954
6955 // bonus against target aura mechanic
6957 {
6958 if (victim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
6959 return true;
6960 return false;
6961 });
6962
6963 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6964 if (spellEffectInfo.Mechanic)
6966 else if (spellProto->Mechanic)
6968
6969 // Custom scripted damage
6970 switch (spellProto->SpellFamilyName)
6971 {
6972 case SPELLFAMILY_MAGE:
6973 // Ice Lance (no unique family flag)
6974 if (spellProto->Id == 228598)
6975 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6976 DoneTotalMod *= 3.0f;
6977 break;
6979 // Shadow Bite (30% increase from each dot)
6980 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
6981 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
6982 AddPct(DoneTotalMod, 30 * count);
6983
6984 // Drain Soul - increased damage for targets under 20% HP
6985 if (spellProto->Id == 198590)
6987 DoneTotalMod *= 2;
6988 break;
6989 }
6990
6991 return DoneTotalMod;
6992}
6993
6994int32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const
6995{
6996 if (!spellProto || damagetype == DIRECT_DAMAGE)
6997 return pdamage;
6998
6999 float TakenTotalMod = 1.0f;
7000
7001 // Mod damage from spell mechanic
7002 if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
7003 {
7004 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
7005 {
7006 if (mechanicMask & uint64(UI64LIT(1) << aurEff->GetMiscValue()))
7007 return true;
7008 return false;
7009 });
7010 }
7011
7012 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
7013 if (cheatDeath->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
7014 AddPct(TakenTotalMod, cheatDeath->GetAmount());
7015
7016 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
7018 {
7019 // Versatility
7020 if (Player* modOwner = GetSpellModOwner())
7021 {
7022 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
7023 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
7024 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
7025 }
7026
7027 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
7028 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
7030
7031 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_TAKEN_BY_LABEL, [spellProto](AuraEffect const* aurEff) -> bool
7032 {
7033 return spellProto->HasLabel(aurEff->GetMiscValue());
7034 });
7035
7036 // From caster spells
7037 if (caster)
7038 {
7039 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
7040 {
7041 return aurEff->GetCasterGUID() == caster->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
7042 });
7043
7044 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
7045 {
7046 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto);
7047 });
7048
7049 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER_BY_LABEL, [caster, spellProto](AuraEffect const* aurEff) -> bool
7050 {
7051 return aurEff->GetCasterGUID() == caster->GetGUID() && spellProto->HasLabel(aurEff->GetMiscValue());
7052 });
7053 }
7054
7055 if (damagetype == DOT)
7056 {
7057 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
7058 {
7059 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
7060 });
7061 }
7062 }
7063
7064 // Sanctified Wrath (bypass damage reduction)
7065 if (caster && TakenTotalMod < 1.0f)
7066 {
7067 float damageReduction = 1.0f - TakenTotalMod;
7069 for (AuraEffect const* aurEff : casterIgnoreResist)
7070 {
7071 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
7072 continue;
7073
7074 AddPct(damageReduction, -aurEff->GetAmount());
7075 }
7076
7077 TakenTotalMod = 1.0f - damageReduction;
7078 }
7079
7080 float tmpDamage = pdamage * TakenTotalMod;
7081 return int32(std::max(tmpDamage, 0.0f));
7082}
7083
7085{
7086 Player const* thisPlayer = ToPlayer();
7087 if (thisPlayer)
7088 {
7089 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7090 if (overrideSP > 0.0f)
7091 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7092 }
7093
7094 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
7095
7096 if (thisPlayer)
7097 {
7098 // Base value
7099 DoneAdvertisedBenefit += thisPlayer->GetBaseSpellPowerBonus();
7100
7101 if (thisPlayer->GetPrimaryStat() == STAT_INTELLECT)
7102 DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7103
7104 // Damage bonus from stats
7106 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
7107 {
7108 if ((aurEff->GetMiscValue() & schoolMask) != 0)
7109 {
7110 // stat used stored in miscValueB for this aura
7111 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
7112 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
7113 }
7114 }
7115
7116 }
7117
7118 return DoneAdvertisedBenefit;
7119}
7120
7121float Unit::SpellCritChanceDone(Spell* spell, AuraEffect const* aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7122{
7123 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7125 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
7126 return 0.0f;
7127
7128 // not critting spell
7129 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7130 return 0.0f;
7131
7132 float crit_chance = 0.0f;
7133 switch (spellInfo->DmgClass)
7134 {
7137 {
7138 auto getPhysicalCritChance = [&]
7139 {
7140 return GetUnitCriticalChanceDone(attackType);
7141 };
7142
7143 auto getMagicCritChance = [&]
7144 {
7145 if (Player const* thisPlayer = ToPlayer())
7146 return *thisPlayer->m_activePlayerData->SpellCritPercentage;
7147
7148 return m_baseSpellCritChance;
7149 };
7150
7151 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
7152 crit_chance = std::max(crit_chance, getPhysicalCritChance());
7153
7154 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
7155 crit_chance = std::max(crit_chance, getMagicCritChance());
7156 break;
7157 }
7160 {
7161 crit_chance += GetUnitCriticalChanceDone(attackType);
7162 break;
7163 }
7164 default:
7165 return 0.0f;
7166 }
7167 // percent done
7168 // only players use intelligence for critical chance computations
7169 if (Player* modOwner = GetSpellModOwner())
7170 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritChance, crit_chance);
7171
7172 return std::max(crit_chance, 0.0f);
7173}
7174
7175float Unit::SpellCritChanceTaken(Unit const* caster, Spell* spell, AuraEffect const* aurEff, SpellSchoolMask /*schoolMask*/, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7176{
7177 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7178 // not critting spell
7179 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7180 return 0.0f;
7181
7182 float crit_chance = doneChance;
7183 switch (spellInfo->DmgClass)
7184 {
7186 {
7187 // taken
7188 if (!spellInfo->IsPositive())
7189 {
7190 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7192 }
7193
7194 if (caster)
7195 {
7196 // scripted (increase crit chance ... against ... target by x%
7197 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7198 for (AuraEffect const* aurEff : mOverrideClassScript)
7199 {
7200 if (!aurEff->IsAffectingSpell(spellInfo))
7201 continue;
7202
7203 switch (aurEff->GetMiscValue())
7204 {
7205 case 911: // Shatter
7206 if (HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7207 {
7208 crit_chance *= 1.5f;
7209 if (AuraEffect const* eff = aurEff->GetBase()->GetEffect(EFFECT_1))
7210 crit_chance += eff->GetAmount();
7211 }
7212 break;
7213 default:
7214 break;
7215 }
7216 }
7217 // Custom crit by class
7218 switch (spellInfo->SpellFamilyName)
7219 {
7220 case SPELLFAMILY_ROGUE:
7221 // Shiv-applied poisons can't crit
7222 if (caster->FindCurrentSpellBySpellId(5938))
7223 crit_chance = 0.0f;
7224 break;
7225 }
7226
7227 // Spell crit suppression
7228 if (GetTypeId() == TYPEID_UNIT)
7229 {
7230 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7231 crit_chance -= levelDiff * 1.0f;
7232 }
7233 }
7234 break;
7235 }
7237
7239 if (caster)
7240 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7241 break;
7243 default:
7244 return 0.f;
7245 }
7246
7247 // for this types the bonus was already added in GetUnitCriticalChance, do not add twice
7248 if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
7249 {
7250 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7251 {
7252 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo);
7253 });
7254 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster](AuraEffect const* aurEff) -> bool
7255 {
7256 return aurEff->GetCasterGUID() == caster->GetGUID();
7257 });
7258 crit_chance += caster->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH, [this](AuraEffect const* aurEff)
7259 {
7260 return !HealthBelowPct(aurEff->GetMiscValueB());
7261 });
7262 if (TempSummon const* tempSummon = caster->ToTempSummon())
7263 {
7264 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
7265 {
7266 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
7267 });
7268 }
7269 }
7270
7271 // call script handlers
7272 if (spell)
7273 spell->CallScriptCalcCritChanceHandlers(this, crit_chance);
7274 else
7275 aurEff->GetBase()->CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(GetGUID()), this, crit_chance);
7276
7277 return std::max(crit_chance, 0.0f);
7278}
7279
7280/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7281{
7282 // Calculate critical bonus
7283 int32 crit_bonus = damage * 2;
7284 float crit_mod = 0.0f;
7285
7286 if (caster)
7287 {
7288 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7289
7290 if (crit_bonus != 0)
7291 AddPct(crit_bonus, crit_mod);
7292
7294 {
7295 return aurEff->GetCasterGUID() == caster->GetGUID();
7296 }));
7297
7298 crit_bonus -= damage;
7299
7300 // adds additional damage to critBonus (from talents)
7301 if (Player* modOwner = caster->GetSpellModOwner())
7302 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7303
7304 crit_bonus += damage;
7305 }
7306
7307 return crit_bonus;
7308}
7309
7310/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/)
7311{
7312 // Calculate critical bonus
7313 int32 crit_bonus = damage;
7314
7315 // adds additional damage to critBonus (from talents)
7316 if (caster)
7317 if (Player* modOwner = caster->GetSpellModOwner())
7318 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7319
7320 damage += crit_bonus;
7321
7322 if (caster)
7323 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7324
7325 return damage;
7326}
7327
7328int32 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
7329{
7330 // For totems get healing bonus from owner (statue isn't totem in fact)
7331 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7332 if (Unit* owner = GetOwner())
7333 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack, spell, aurEff);
7334
7335 // No bonus healing for potion spells
7336 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7337 return healamount;
7338
7339 int32 DoneTotal = 0;
7340 float DoneTotalMod = SpellHealingPctDone(victim, spellProto);
7341
7342 // done scripted mod (take it from owner)
7343 Unit const* owner = GetOwner() ? GetOwner() : this;
7344 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7345 for (AuraEffect const* aurEff : mOverrideClassScript)
7346 {
7347 if (!aurEff->IsAffectingSpell(spellProto))
7348 continue;
7349
7350 switch (aurEff->GetMiscValue())
7351 {
7352 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
7353 DoneTotal += aurEff->GetAmount();
7354 break;
7355 default:
7356 break;
7357 }
7358 }
7359
7360 // Done fixed damage bonus auras
7361 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7362 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7363 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7364
7365 // Pets just add their bonus damage to their spell damage
7366 // note that their spell damage is just gain of their own auras
7368 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7369
7370 // Check for table values
7371 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7372 {
7373 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
7374 if (Player* modOwner = GetSpellModOwner())
7375 {
7376 attackPowerCoeff *= 100.0f;
7377 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
7378 attackPowerCoeff /= 100.0f;
7379 }
7380
7381 WeaponAttackType const attType = [&]()
7382 {
7383 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
7384 return RANGED_ATTACK;
7385
7387 return OFF_ATTACK;
7388
7389 return BASE_ATTACK;
7390 }();
7392 attackPowerBonus += GetTotalAttackPowerValue(attType);
7393 DoneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
7394 }
7395
7396 // Default calculation
7397 if (DoneAdvertisedBenefit)
7398 {
7399 float coeff = spellEffectInfo.BonusCoefficient;
7400 if (Player* modOwner = GetSpellModOwner())
7401 {
7402 coeff *= 100.0f;
7403 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7404 coeff /= 100.0f;
7405 }
7406
7407 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
7408 }
7409
7410 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7411 {
7412 switch (otherSpellEffect.ApplyAuraName)
7413 {
7414 // Bonus healing does not apply to these spells
7417 DoneTotal = 0;
7418 break;
7419 default:
7420 break;
7421 }
7422 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7423 DoneTotal = 0;
7424 }
7425
7426 if (spell)
7427 spell->CallScriptCalcHealingHandlers(spellEffectInfo, victim, healamount, DoneTotal, DoneTotalMod);
7428 else if (aurEff)
7429 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, healamount, DoneTotal, DoneTotalMod);
7430
7431 float heal = float(healamount + DoneTotal) * DoneTotalMod;
7432
7433 // apply spellmod to Done amount
7434 if (Player* modOwner = GetSpellModOwner())
7435 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal);
7436
7437 return int32(std::max(heal, 0.0f));
7438}
7439
7440float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7441{
7442 // For totems get healing bonus from owner
7443 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7444 if (Unit* owner = GetOwner())
7445 return owner->SpellHealingPctDone(victim, spellProto);
7446
7447 // Some spells don't benefit from done mods
7449 return 1.0f;
7450
7451 // Some spells don't benefit from done mods
7453 return 1.0f;
7454
7455 // Some spells don't benefit from done mods
7457 return 1.0f;
7458
7459 // No bonus healing for potion spells
7460 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7461 return 1.0f;
7462
7463 float DoneTotalMod = 1.0f;
7464
7465 // Healing done percent
7466 if (Player const* thisPlayer = ToPlayer())
7467 {
7468 float maxModDamagePercentSchool = 0.0f;
7469 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
7470 if (spellProto->GetSchoolMask() & (1 << i))
7471 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModHealingDonePercent[i]);
7472
7473 DoneTotalMod *= maxModDamagePercentSchool;
7474 }
7475 else // SPELL_AURA_MOD_HEALING_DONE_PERCENT is included in m_activePlayerData->ModHealingDonePercent for players
7477
7478 // bonus against aurastate
7479 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7480 {
7481 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
7482 return true;
7483 return false;
7484 });
7485
7486 // bonus from missing health of target
7487 float healthPctDiff = 100.0f - victim->GetHealthPct();
7489 if (healingDonePctVsTargetHealth->IsAffectingSpell(spellProto))
7490 AddPct(DoneTotalMod, CalculatePct(healingDonePctVsTargetHealth->GetAmount(), healthPctDiff));
7491
7492 return DoneTotalMod;
7493}
7494
7495int32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const
7496{
7497 bool allowPositive = !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_HEALING_MODIFIERS);
7499 if (!allowPositive && !allowNegative)
7500 return healamount;
7501
7502 float TakenTotalMod = 1.0f;
7503
7504 // Healing taken percent
7505 if (allowNegative)
7506 {
7508 if (minval)
7509 AddPct(TakenTotalMod, minval);
7510
7511 if (damagetype == DOT)
7512 {
7513 // Healing over time taken percent
7514 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7515 if (minval_hot)
7516 AddPct(TakenTotalMod, minval_hot);
7517 }
7518 }
7519
7520 if (allowPositive)
7521 {
7523 if (maxval)
7524 AddPct(TakenTotalMod, maxval);
7525
7526 if (damagetype == DOT)
7527 {
7528 // Healing over time taken percent
7529 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7530 if (maxval_hot)
7531 AddPct(TakenTotalMod, maxval_hot);
7532 }
7533
7534 // Nourish cast
7535 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7536 {
7537 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7539 // increase healing by 20%
7540 TakenTotalMod *= 1.2f;
7541 }
7542 }
7543
7544 if (caster)
7545 {
7546 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7547 {
7548 if (caster->GetGUID() != aurEff->GetCasterGUID() || !aurEff->IsAffectingSpell(spellProto))
7549 return false;
7550
7551 if (aurEff->GetAmount() > 0)
7552 {
7553 if (!allowPositive)
7554 return false;
7555 }
7556 else if (!allowNegative)
7557 return false;
7558
7559 return true;
7560 });
7561
7562 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER, [caster, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7563 {
7564 if (aurEff->GetCasterGUID() != caster->GetGUID())
7565 return false;
7566
7567 if (aurEff->GetAmount() > 0)
7568 {
7569 if (!allowPositive)
7570 return false;
7571 }
7572 else if (!allowNegative)
7573 return false;
7574
7575 return true;
7576 });
7577 }
7578
7579 float heal = healamount * TakenTotalMod;
7580 return int32(std::max(heal, 0.0f));
7581}
7582
7584{
7585 if (Player const* thisPlayer = ToPlayer())
7586 {
7587 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7588 if (overrideSP > 0.0f)
7589 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7590 }
7591
7592 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7593 {
7594 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7595 return true;
7596 return false;
7597 });
7598
7599 // Healing bonus of spirit, intellect and strength
7600 if (GetTypeId() == TYPEID_PLAYER)
7601 {
7602 // Base value
7603 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7604
7605 // Check if we are ever using mana - PaperDollFrame.lua
7607 advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7608
7609 // Healing bonus from stats
7611 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7612 {
7613 // stat used dependent from misc value (stat index)
7614 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7615 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7616 }
7617 }
7618 return advertisedBenefit;
7619}
7620
7622{
7623 return SpellBaseHealingBonusDone(schoolMask);
7624}
7625
7626int32 Unit::SpellAbsorbBonusDone(Unit* victim, SpellInfo const* spellProto, int32 absorbamount, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, AuraEffect const* aurEff /*= nullptr*/) const
7627{
7628 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7629 if (Unit* owner = GetOwner())
7630 return owner->SpellAbsorbBonusDone(victim, spellProto, absorbamount, spellEffectInfo, stack, aurEff);
7631
7634 return absorbamount;
7635
7636 int32 doneTotal = 0;
7637 float doneTotalMod = SpellAbsorbPctDone(victim, spellProto);
7638
7639 int32 doneAdvertisedBenefit = SpellBaseAbsorbBonusDone(spellProto->GetSchoolMask());
7640 doneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7641
7643 doneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7644
7645 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7646 {
7647 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
7648 if (Player* modOwner = GetSpellModOwner())
7649 {
7650 attackPowerCoeff *= 100.0f;
7651 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
7652 attackPowerCoeff /= 100.0f;
7653 }
7654
7655 WeaponAttackType const attType = [&]()
7656 {
7657 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
7658 return RANGED_ATTACK;
7659
7661 return OFF_ATTACK;
7662
7663 return BASE_ATTACK;
7664 }();
7666 attackPowerBonus += GetTotalAttackPowerValue(attType);
7667 doneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
7668 }
7669
7670 if (doneAdvertisedBenefit)
7671 {
7672 float coeff = spellEffectInfo.BonusCoefficient;
7673
7674 if (Player* modOwner = GetSpellModOwner())
7675 {
7676 coeff *= 100.f;
7677 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7678 coeff /= 100.f;
7679 }
7680
7681 doneTotal += int32(doneAdvertisedBenefit * coeff * stack);
7682 }
7683
7684 if (aurEff)
7685 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, absorbamount, doneTotal, doneTotalMod);
7686
7687 float absorbAmount = float(absorbamount + doneTotal) * doneTotalMod;
7688
7689 return static_cast<int32>(std::round(absorbAmount));
7690}
7691
7692float Unit::SpellAbsorbPctDone(Unit* victim, SpellInfo const* spellProto) const
7693{
7694 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7695 if (Unit* owner = GetOwner())
7696 return owner->SpellAbsorbPctDone(victim, spellProto);
7697
7698 float doneTotalMod = 1.f;
7699
7700 if (Player* modOwner = GetSpellModOwner())
7701 AddPct(doneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
7702
7704
7705 return doneTotalMod;
7706}
7707
7708int32 Unit::SpellAbsorbBonusTaken(Unit* /*caster*/, SpellInfo const* spellProto, int32 absorbamount) const
7709{
7711 return absorbamount;
7712
7713 int32 doneTotal = 0;
7714 float takenTotalMod = 1.f;
7715
7717
7718 float absorb = float(absorbamount + doneTotal) * takenTotalMod;
7719
7720 return static_cast<int32>(std::round(absorb));
7721}
7722
7723bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7724{
7725 if (!spellInfo)
7726 return false;
7727
7728 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7729 {
7731 if (!requireImmunityPurgesEffectAttribute)
7732 return range.begin() != range.end();
7733
7734 return std::ranges::any_of(range, [](uint32 immunitySpellId)
7735 {
7736 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
7737 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7738 return true;
7739
7740 return false;
7742 };
7743
7744 // Single spell immunity.
7746 if (hasImmunity(idList, spellInfo->Id))
7747 return true;
7748
7750 return false;
7751
7752 if (uint32 dispel = spellInfo->Dispel)
7753 {
7755 if (hasImmunity(dispelList, dispel))
7756 return true;
7757 }
7758
7759 // Spells that don't have effectMechanics.
7760 if (uint32 mechanic = spellInfo->Mechanic)
7761 {
7763 if (hasImmunity(mechanicList, mechanic))
7764 return true;
7765 }
7766
7767 bool immuneToAllEffects = true;
7768 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7769 {
7770 // State/effect immunities applied by aura expect full spell immunity
7771 // Ignore effects with mechanic, they are supposed to be checked separately
7772 if (!spellEffectInfo.IsEffect() || !(effectMask & (1 << spellEffectInfo.EffectIndex)))
7773 continue;
7774 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7775 {
7776 immuneToAllEffects = false;
7777 break;
7778 }
7780 return true;
7781 }
7782
7783 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7784 return true;
7785
7786 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7787 {
7788 uint32 schoolImmunityMask = 0;
7790 for (auto [auraSchoolImmunityMask, immunityAuraId] : schoolList)
7791 {
7792 if ((auraSchoolImmunityMask & schoolMask) == 0)
7793 continue;
7794
7795 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7796 if (requireImmunityPurgesEffectAttribute)
7797 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7798 continue;
7799
7800 if (!(spellInfo->NegativeEffects.to_ulong() & effectMask) && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
7801 continue;
7802
7803 if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7804 continue;
7805
7806 schoolImmunityMask |= auraSchoolImmunityMask;
7807 }
7808 if ((schoolImmunityMask & schoolMask) == schoolMask)
7809 return true;
7810 }
7811
7812 return false;
7813}
7814
7816{
7817 uint32 mask = 0;
7819 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7820 mask |= itr->first;
7821
7822 return mask;
7823}
7824
7826{
7827 uint32 mask = 0;
7829 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7830 mask |= itr->first;
7831
7832 return mask;
7833}
7834
7836{
7837 uint64 mask = 0;
7839 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7840 mask |= (UI64LIT(1) << itr->first);
7841
7842 return mask;
7843}
7844
7846{
7847 SpellOtherImmunity mask = { };
7849 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7850 mask |= SpellOtherImmunity(itr->first);
7851
7852 return mask;
7853}
7854
7856{
7857 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7858 return false;
7859
7860 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7861 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7862 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7863 return true;
7864
7865 // If m_immuneToDamage type contain magic, IMMUNE damage.
7866 uint32 damageImmunityMask = GetDamageImmunityMask();
7867 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7868 return true;
7869
7870 return false;
7871}
7872
7873bool Unit::IsImmunedToDamage(WorldObject const* /*caster*/, SpellInfo const* spellInfo, SpellEffectInfo const* spellEffectInfo /*= nullptr*/) const
7874{
7875 if (!spellInfo)
7876 return false;
7877
7879 return false;
7880
7881 if (spellEffectInfo && spellEffectInfo->EffectAttributes.HasFlag(SpellEffectAttributes::NoImmunity))
7882 return false;
7883
7884 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7885 {
7886 auto hasImmunity = [&](SpellImmuneContainer const& container)
7887 {
7888 uint32 schoolImmunityMask = 0;
7889 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
7890 {
7891 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7892 if (spellInfo->IsPositive() && !(immuneAuraInfo && immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
7893 continue;
7894
7895 if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
7896 continue;
7897
7898 schoolImmunityMask |= immunitySchoolMask;
7899 }
7900
7901 // // We need to be immune to all types
7902 return (schoolImmunityMask & schoolMask) == schoolMask;
7903 };
7904
7905 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7906 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
7907 return true;
7908
7909 // If m_immuneToDamage type contain magic, IMMUNE damage.
7910 if (hasImmunity(m_spellImmune[IMMUNITY_DAMAGE]))
7911 return true;
7912 }
7913
7914 return false;
7915}
7916
7917bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* /*caster*/,
7918 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7919{
7920 if (!spellInfo)
7921 return false;
7922
7924 return false;
7925
7927 return false;
7928
7929 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7930 {
7932 if (!requireImmunityPurgesEffectAttribute)
7933 return range.begin() != range.end();
7934
7935 return std::ranges::any_of(range, [](uint32 immunitySpellId)
7936 {
7937 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
7938 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7939 return true;
7940
7941 return false;
7943 };
7944
7945 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7946 auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
7947 if (hasImmunity(effectList, spellEffectInfo.Effect))
7948 return true;
7949
7950 if (uint32 mechanic = spellEffectInfo.Mechanic)
7951 {
7953 if (hasImmunity(mechanicList, mechanic))
7954 return true;
7955 }
7956
7957 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7958 {
7959 if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
7960 {
7962 if (hasImmunity(list, aura))
7963 return true;
7964 }
7965
7967 {
7968 // Check for immune to application of harmful magical effects
7970 {
7971 if (!(immuneAuraApply->GetMiscValue() & spellInfo->GetSchoolMask())) // Check school
7972 continue;
7973
7974 if (!spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex)) // Harmful
7975 return true;
7976
7977 if (immuneAuraApply->GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)) // Friendly
7978 return true;
7979 }
7980 }
7981 }
7982
7983 return false;
7984}
7985
7986bool Unit::IsImmunedToAuraPeriodicTick(WorldObject const* /*caster*/, AuraEffect const* auraEffect) const
7987{
7988 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) /*only school immunities are checked in this function*/)
7989 return false;
7990
7992 return false;
7993
7994 if (uint32 schoolMask = auraEffect->GetSpellInfo()->GetSchoolMask())
7995 {
7996 auto hasImmunity = [&](SpellImmuneContainer const& container)
7997 {
7998 bool isPositive = auraEffect->GetBase()->GetApplicationOfTarget(GetGUID())->IsPositive();
7999 uint32 schoolImmunityMask = 0;
8000 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
8001 {
8002 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
8003 if (isPositive && !(immuneAuraInfo && immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
8004 continue;
8005
8006 schoolImmunityMask |= immunitySchoolMask;
8007 }
8008
8009 // // We need to be immune to all types
8010 return (schoolImmunityMask & schoolMask) == schoolMask;
8011 };
8012
8013 // If m_immuneToSchool type contain this school type, IMMUNE damage.
8014 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
8015 return true;
8016 }
8017
8018 return false;
8019}
8020
8021int32 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*/)
8022{
8023 if (!pVictim || damage == 0)
8024 return 0;
8025
8026 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8027
8028 // Done fixed damage bonus auras
8029 int32 DoneFlatBenefit = 0;
8030
8031 // ..done
8032 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
8033
8034 // ..done
8035 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8036
8037 // ..done (base at attack power for marked target and base at attack power for creature type)
8038 int32 APbonus = 0;
8039
8040 if (attType == RANGED_ATTACK)
8041 {
8043
8044 // ..done (base at attack power and creature type)
8046 }
8047 else
8048 {
8050
8051 // ..done (base at attack power and creature type)
8053 }
8054
8055 if (APbonus != 0) // Can be negative
8056 {
8057 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
8058 DoneFlatBenefit += int32(APbonus / 3.5f * GetAPMultiplier(attType, normalized));
8059 }
8060
8061 // Done total percent damage auras
8062 float DoneTotalMod = 1.0f;
8063
8064 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8065
8066 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
8067 {
8068 // Some spells don't benefit from pct done mods
8069 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
8070 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS))
8071 {
8072 float maxModDamagePercentSchool = 0.0f;
8073 if (Player const* thisPlayer = ToPlayer())
8074 {
8075 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
8076 if (schoolMask & (1 << i))
8077 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
8078 }
8079 else
8080 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
8081
8082 DoneTotalMod *= maxModDamagePercentSchool;
8083 }
8084 }
8085
8086 if (!spellProto)
8087 {
8088 // melee attack
8090 AddPct(DoneTotalMod, autoAttackDamage->GetAmount());
8091 }
8092
8094
8095 // bonus against aurastate
8096 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [pVictim](AuraEffect const* aurEff) -> bool
8097 {
8098 if (pVictim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
8099 return true;
8100 return false;
8101 });
8102
8103 // bonus against target aura mechanic
8105 {
8106 if (pVictim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
8107 return true;
8108 return false;
8109 });
8110
8111 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
8112 if (mechanic != MECHANIC_NONE)
8114 else if (spellProto && spellProto->Mechanic)
8116
8117 if (spell)
8118 spell->CallScriptCalcDamageHandlers(*spellEffectInfo, pVictim, damage, DoneFlatBenefit, DoneTotalMod);
8119 else if (aurEff)
8120 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID()), pVictim, damage, DoneFlatBenefit, DoneTotalMod);
8121
8122 float damageF = float(damage + DoneFlatBenefit) * DoneTotalMod;
8123
8124 // apply spellmod to Done damage
8125 if (spellProto)
8126 if (Player* modOwner = GetSpellModOwner())
8127 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF);
8128
8129 // bonus result can be negative
8130 return int32(std::max(damageF, 0.0f));
8131}
8132
8133int32 Unit::MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
8134{
8135 if (pdamage == 0)
8136 return 0;
8137
8138 int32 TakenFlatBenefit = 0;
8139
8140 // ..taken
8142
8143 if (attType != RANGED_ATTACK)
8145 else
8147
8148 if ((TakenFlatBenefit < 0) && (pdamage < -TakenFlatBenefit))
8149 return 0;
8150
8151 // Taken total percent damage auras
8152 float TakenTotalMod = 1.0f;
8153
8154 // ..taken
8156
8157 // .. taken pct (special attacks)
8158 if (spellProto)
8159 {
8160 // From caster spells
8161 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8162 {
8163 return aurEff->GetCasterGUID() == attacker->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
8164 });
8165
8166 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8167 {
8168 return aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto);
8169 });
8170
8171 // Mod damage from spell mechanic
8172 uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
8173
8174 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
8175 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
8176 mechanicMask |= (1 << MECHANIC_BLEED);
8177
8178 if (mechanicMask)
8179 {
8180 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
8181 {
8182 if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
8183 return true;
8184 return false;
8185 });
8186 }
8187
8188 if (damagetype == DOT)
8189 {
8190 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
8191 {
8192 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
8193 });
8194 }
8195 }
8196 else // melee attack
8197 {
8198 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER, [attacker](AuraEffect const* aurEff) -> bool
8199 {
8200 return aurEff->GetCasterGUID() == attacker->GetGUID();
8201 });
8202 }
8203
8204 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
8205 AddPct(TakenTotalMod, cheatDeath->GetAmount());
8206
8207 if (attType != RANGED_ATTACK)
8209 else
8211
8212 // Versatility
8213 if (Player* modOwner = GetSpellModOwner())
8214 {
8215 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
8216 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
8217 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
8218 }
8219
8220 // Sanctified Wrath (bypass damage reduction)
8221 if (TakenTotalMod < 1.0f)
8222 {
8223 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8224
8225 float damageReduction = 1.0f - TakenTotalMod;
8227 for (AuraEffect const* aurEff : casterIgnoreResist)
8228 {
8229 if (!(aurEff->GetMiscValue() & attackSchoolMask))
8230 continue;
8231
8232 AddPct(damageReduction, -aurEff->GetAmount());
8233 }
8234
8235 TakenTotalMod = 1.0f - damageReduction;
8236 }
8237
8238 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
8239 return int32(std::max(tmpDamage, 0.0f));
8240}
8241
8242void Unit::ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
8243{
8244 if (apply)
8245 m_spellImmune[op].emplace(type, spellId);
8246 else
8247 {
8248 auto bounds = m_spellImmune[op].equal_range(type);
8249 for (auto itr = bounds.first; itr != bounds.second;)
8250 {
8251 if (itr->second == spellId)
8252 itr = m_spellImmune[op].erase(itr);
8253 else
8254 ++itr;
8255 }
8256 }
8257}
8258
8260{
8261 // normalized proc chance for weapon attack speed
8262 // (odd formula...)
8264 return (GetBaseAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8266 return (GetBaseAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8267 return 0;
8268}
8269
8270float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
8271{
8272 // proc per minute chance calculation
8273 if (PPM <= 0)
8274 return 0.0f;
8275
8276 // Apply chance modifer aura
8277 if (spellProto)
8278 if (Player* modOwner = GetSpellModOwner())
8279 modOwner->ApplySpellMod(spellProto, SpellModOp::ProcFrequency, PPM);
8280
8281 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8282}
8283
8284void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
8285{
8287 if (mount)
8288 SetMountDisplayId(mount);
8289
8291
8293
8294 if (Player* player = ToPlayer())
8295 {
8296 // mount as a vehicle
8297 if (VehicleId)
8298 {
8299 if (CreateVehicleKit(VehicleId, creatureEntry))
8300 {
8301 player->SendOnCancelExpectedVehicleRideAura();
8302
8303 // mounts can also have accessories
8305 }
8306 }
8307
8308 // disable pet controls
8309 player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
8310
8311 player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8312 }
8313
8315}
8316
8318{
8319 if (!IsMounted())
8320 return;
8321
8324
8325 if (Player* thisPlayer = ToPlayer())
8326 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8327
8329
8330 // dismount as a vehicle
8332 {
8333 // Remove vehicle from player
8335 }
8336
8338
8339 // only resummon old pet if the player is already added to a map
8340 // this prevents adding a pet to a not created map which would otherwise cause a crash
8341 // (it could probably happen when logging in after a previous crash)
8342 if (Player* player = ToPlayer())
8343 {
8344 player->EnablePetControlsOnDismount();
8345 player->ResummonPetTemporaryUnSummonedIfAny();
8346 player->ResummonBattlePetTemporaryUnSummonedIfAny();
8347 }
8348}
8349
8351{
8353 return;
8354
8356 {
8357 SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
8358 return force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive());
8359 });
8360}
8361
8363{
8364 if (!mountType)
8365 return nullptr;
8366
8367 DB2Manager::MountTypeXCapabilitySet const* capabilities = sDB2Manager.GetMountCapabilities(mountType);
8368 if (!capabilities)
8369 return nullptr;
8370
8371 uint32 areaId = GetAreaId();
8372 uint32 ridingSkill = 5000;
8374 bool isSubmerged = false;
8375 bool isInWater = false;
8376
8377 if (GetTypeId() == TYPEID_PLAYER)
8378 ridingSkill = ToPlayer()->GetSkillValue(SKILL_RIDING);
8379
8381 {
8383 mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
8384 }
8385 else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(areaId))
8386 mountFlags = areaTable->GetMountFlags();
8387
8388 LiquidData liquid;
8389 ZLiquidStatus liquidStatus = GetMap()->GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), {}, &liquid);
8390 isSubmerged = (liquidStatus & LIQUID_MAP_UNDER_WATER) != 0 || HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
8391 isInWater = (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
8392
8393 for (MountTypeXCapabilityEntry const* mountTypeXCapability : *capabilities)
8394 {
8395 MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeXCapability->MountCapabilityID);
8396 if (!mountCapability)
8397 continue;
8398
8399 if (ridingSkill < mountCapability->ReqRidingSkill)
8400 continue;
8401
8402 if (!(mountCapability->Flags & MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS))
8403 {
8404 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND && !(mountFlags.HasFlag(AreaMountFlags::AllowGroundMounts)))
8405 continue;
8406 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
8407 continue;
8409 continue;
8411 continue;
8412 }
8413
8414 if (!isSubmerged)
8415 {
8416 if (!isInWater)
8417 {
8418 // player is completely out of water
8419 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND))
8420 continue;
8421 }
8422 // player is on water surface
8423 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8424 continue;
8425 }
8426 else if (isInWater)
8427 {
8428 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_UNDERWATER))
8429 continue;
8430 }
8431 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8432 continue;
8433
8434 if (mountCapability->ReqMapID != -1 &&
8435 int32(GetMapId()) != mountCapability->ReqMapID &&
8436 GetMap()->GetEntry()->CosmeticParentMapID != mountCapability->ReqMapID &&
8437 GetMap()->GetEntry()->ParentMapID != mountCapability->ReqMapID)
8438 continue;
8439
8440 if (mountCapability->ReqAreaID && !DB2Manager::IsInArea(areaId, mountCapability->ReqAreaID))
8441 continue;
8442
8443 if (mountCapability->ReqSpellAuraID && !HasAura(mountCapability->ReqSpellAuraID))
8444 continue;
8445
8446 if (mountCapability->ReqSpellKnownID && !HasSpell(mountCapability->ReqSpellKnownID))
8447 continue;
8448
8449 if (Player const* thisPlayer = ToPlayer())
8450 if (!ConditionMgr::IsPlayerMeetingCondition(thisPlayer, mountCapability->PlayerConditionID))
8451 continue;
8452
8453 return mountCapability;
8454 }
8455
8456 return nullptr;
8457}
8458
8460{
8461 if (IsLoading())
8462 return;
8463
8464 if (SpellShapeshiftFormEntry const* spellShapeshiftForm = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()))
8465 if (uint32 mountType = spellShapeshiftForm->MountTypeID)
8466 if (!GetMountCapability(mountType))
8468
8470 for (AuraEffect* aurEff : mounts)
8471 {
8472 aurEff->RecalculateAmount();
8473 if (!aurEff->GetAmountAsInt())
8474 aurEff->GetBase()->Remove();
8475 else if (MountCapabilityEntry const* capability = sMountCapabilityStore.LookupEntry(aurEff->GetAmountAsInt())) // aura may get removed by interrupt flag, reapply
8476 {
8477 SetFlightCapabilityID(capability->FlightCapabilityID, true);
8478
8479 if (!HasAura(capability->ModSpellAuraID))
8480 CastSpell(this, capability->ModSpellAuraID, aurEff);
8481 }
8482 }
8483}
8484
8493
8495{
8496 if (!enemy)
8497 return;
8498
8499 if (CanHaveThreatList())
8500 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8501 else
8502 SetInCombatWith(enemy);
8503}
8504
8505void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8506{
8507 if (apply)
8508 {
8511 if (!keepCombat)
8513 }
8514 else
8516}
8517
8518void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8519{
8520 if (apply)
8521 {
8524 if (!keepCombat)
8525 {
8526 std::list<CombatReference*> toEnd;
8527 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8528 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8529 toEnd.push_back(pair.second);
8530 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8531 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8532 toEnd.push_back(pair.second);
8533 for (CombatReference* ref : toEnd)
8534 ref->EndCombat();
8535 }
8536 }
8537 else
8539}
8540
8541void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8542{
8543 if (apply)
8544 {
8547 if (!keepCombat)
8548 {
8549 std::list<CombatReference*> toEnd;
8550 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8551 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8552 toEnd.push_back(pair.second);
8553 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8554 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8555 toEnd.push_back(pair.second);
8556 for (CombatReference* ref : toEnd)
8557 ref->EndCombat();
8558 }
8559 }
8560 else
8562}
8563
8565{
8566 if (apply)
8568 else
8570}
8571
8572void Unit::SetCannotTurn(bool apply)
8573{
8574 if (apply)
8576 else
8578}
8579
8581{
8583}
8584
8585bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8586{
8587 if (!IsAlive())
8588 return false;
8589
8591 return false;
8592
8593 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8594 return false;
8595
8596 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8597}
8598
8600{
8601 int64 gain = 0;
8602
8603 if (dVal == 0)
8604 return 0;
8605
8606 int64 curHealth = (int64)GetHealth();
8607
8608 int64 val = dVal + curHealth;
8609 if (val <= 0)
8610 {
8611 SetHealth(0);
8612 return -curHealth;
8613 }
8614
8615 int64 maxHealth = (int64)GetMaxHealth();
8616
8617 if (val < maxHealth)
8618 {
8619 SetHealth(val);
8620 gain = val - curHealth;
8621 }
8622 else if (curHealth != maxHealth)
8623 {
8624 SetHealth(maxHealth);
8625 gain = maxHealth - curHealth;
8626 }
8627
8628 if (dVal < 0)
8629 {
8631 packet.Guid = GetGUID();
8632 packet.Health = GetHealth();
8633
8635 player->GetSession()->SendPacket(packet.Write());
8636 }
8637
8638 return gain;
8639}
8640
8642{
8643 int64 gain = 0;
8644
8645 if (dVal == 0)
8646 return 0;
8647
8648 int64 curHealth = (int64)GetHealth();
8649
8650 int64 val = dVal + curHealth;
8651 if (val <= 0)
8652 {
8653 return -curHealth;
8654 }
8655
8656 int64 maxHealth = (int64)GetMaxHealth();
8657
8658 if (val < maxHealth)
8659 gain = dVal;
8660 else if (curHealth != maxHealth)
8661 gain = maxHealth - curHealth;
8662
8663 return gain;
8664}
8665
8667{
8669 return;
8670
8672 for (AuraEffect const* effect : effects)
8673 {
8674 SpellEffectValue triggerHealthPct = effect->GetAmount();
8675 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
8676 uint64 threshold = CountPctFromMaxHealth(triggerHealthPct);
8677
8678 switch (AuraTriggerOnHealthChangeDirection(effect->GetMiscValue()))
8679 {
8681 if (newVal < threshold || oldVal > threshold)
8682 continue;
8683 break;
8685 if (newVal > threshold || oldVal < threshold)
8686 continue;
8687 break;
8688 default:
8689 break;
8690 }
8691
8692 CastSpell(this, triggerSpell, effect);
8693 }
8694}
8695
8696// returns negative amount on power reduction
8697int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8698{
8699 int32 gain = 0;
8700
8701 if (dVal == 0)
8702 return 0;
8703
8704 if (dVal > 0)
8706
8707 int32 curPower = GetPower(power);
8708
8709 int32 val = dVal + curPower;
8710 if (val <= GetMinPower(power))
8711 {
8712 SetPower(power, GetMinPower(power), withPowerUpdate);
8713 return -curPower;
8714 }
8715
8716 int32 maxPower = GetMaxPower(power);
8717
8718 if (val < maxPower)
8719 {
8720 SetPower(power, val, withPowerUpdate);
8721 gain = val - curPower;
8722 }
8723 else if (curPower != maxPower)
8724 {
8725 SetPower(power, maxPower, withPowerUpdate);
8726 gain = maxPower - curPower;
8727 }
8728
8729 return gain;
8730}
8731
8733{
8735 return true;
8736
8737 // Always seen by owner
8739 if (!guid.IsEmpty())
8740 if (seer->GetGUID() == guid)
8741 return true;
8742
8743 if (Player const* seerPlayer = seer->ToPlayer())
8744 if (Unit* owner = GetOwner())
8745 if (Player* ownerPlayer = owner->ToPlayer())
8746 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8747 return true;
8748
8749 return false;
8750}
8751
8753{
8755 return true;
8756
8758 return true;
8759
8760 return false;
8761}
8762
8764{
8766}
8767
8777
8779{
8780 float main_speed_mod = 0.0f;
8781 float stack_bonus = 1.0f;
8782 float non_stack_bonus = 1.0f;
8783
8784 switch (mtype)
8785 {
8786 // Only apply debuffs
8787 case MOVE_FLIGHT_BACK:
8788 case MOVE_RUN_BACK:
8789 case MOVE_SWIM_BACK:
8790 break;
8791 case MOVE_WALK:
8792 return;
8793 case MOVE_RUN:
8794 {
8795 if (IsMounted()) // Use on mount auras
8796 {
8800 }
8801 else
8802 {
8806 }
8807 break;
8808 }
8809 case MOVE_SWIM:
8810 {
8812 break;
8813 }
8814 case MOVE_FLIGHT:
8815 {
8816 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8817 {
8820
8821 // for some spells this mod is applied on vehicle owner
8822 float owner_speed_mod = 0.0f;
8823
8824 if (Unit* owner = GetCharmer())
8825 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8826
8827 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8828 }
8829 else if (IsMounted())
8830 {
8833 }
8834 else // Use not mount (shapeshift for example) auras (should stack)
8836
8838
8839 // Update speed for vehicle if available
8840 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8842 break;
8843 }
8844 default:
8845 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8846 return;
8847 }
8848
8849 // now we ready for speed calculation
8850 float speed = std::max(non_stack_bonus, stack_bonus);
8851 if (main_speed_mod)
8852 AddPct(speed, main_speed_mod);
8853
8854 switch (mtype)
8855 {
8856 case MOVE_RUN:
8857 case MOVE_SWIM:
8858 case MOVE_FLIGHT:
8859 {
8860 // Set creature speed rate
8861 if (GetTypeId() == TYPEID_UNIT)
8862 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8863
8864 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8867 {
8868 if (Creature* creature = ToCreature())
8869 if (CreatureImmunities const* immunities = SpellMgr::GetCreatureImmunities(creature->GetCreatureTemplate()->CreatureImmunitiesId))
8870 if (immunities->Mechanic[MECHANIC_SNARE] || immunities->Mechanic[MECHANIC_DAZE])
8871 break;
8872
8873 // Use speed from aura
8874 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8875 if (speed > max_speed)
8876 speed = max_speed;
8877 }
8878
8879 if (mtype == MOVE_RUN)
8880 {
8881 // force minimum speed rate @ aura 437 SPELL_AURA_MOD_MINIMUM_SPEED_RATE
8883 {
8884 float minSpeed = minSpeedMod / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8885 if (speed < minSpeed)
8886 speed = minSpeed;
8887 }
8888 }
8889 break;
8890 }
8891 default:
8892 break;
8893 }
8894
8895 if (Creature* creature = ToCreature())
8896 {
8897 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8898 {
8900 {
8901 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8902 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8903 {
8904 float ownerSpeed = followed->GetSpeedRate(mtype);
8905 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8906 speed = ownerSpeed;
8907 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8908 }
8909 }
8910 }
8911 }
8912
8913 // Apply strongest slow aura mod to speed
8915 if (slow)
8916 AddPct(speed, slow);
8917
8919 {
8920 float baseMinSpeed = 1.0f;
8921 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8922 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8923
8924 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8925 if (speed < min_speed)
8926 speed = min_speed;
8927 }
8928
8929 SetSpeedRate(mtype, speed);
8930}
8931
8933{
8934 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8935}
8936
8937void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8938{
8939 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8940}
8941
8942void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8943{
8944 rate = std::max(rate, 0.01f);
8945
8946 // Update speed only on change
8947 if (m_speed_rate[mtype] == rate)
8948 return;
8949
8950 m_speed_rate[mtype] = rate;
8951
8953
8954 // Spline packets are for creatures and move_update are for players
8955 static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
8956 {
8966 };
8967
8968 if (GetTypeId() == TYPEID_PLAYER)
8969 {
8970 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8971 // and do it only for real sent packets and use run for run/mounted as client expected
8972 ++ToPlayer()->m_forced_speed_changes[mtype];
8973
8974 if (!IsInCombat())
8975 if (Pet* pet = ToPlayer()->GetPet())
8976 pet->SetSpeedRate(mtype, m_speed_rate[mtype]);
8977 }
8978
8979 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
8980 {
8981 // Send notification to self
8982 WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]);
8983 selfpacket.MoverGUID = GetGUID();
8984 selfpacket.SequenceIndex = m_movementCounter++;
8985 selfpacket.Speed = GetSpeed(mtype);
8986 playerMover->GetSession()->SendPacket(selfpacket.Write());
8987
8988 // Send notification to other players
8989 WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]);
8990 packet.Status = &m_movementInfo;
8991 packet.Speed = GetSpeed(mtype);
8992 playerMover->SendMessageToSet(packet.Write(), false);
8993 }
8994 else
8995 {
8996 WorldPackets::Movement::MoveSplineSetSpeed packet(moveTypeToOpcode[mtype][0]);
8997 packet.MoverGUID = GetGUID();
8998 packet.Speed = GetSpeed(mtype);
8999 SendMessageToSet(packet.Write(), true);
9000 }
9001}
9002
9024
9025void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
9026{
9027 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
9028 if (!flightCapabilityEntry)
9029 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
9030
9031 auto [opcode, newValue, rateAura] = [&]
9032 {
9033 switch (speedType)
9034 {
9037 case ADV_FLYING_MAX_VEL:
9038 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_MAX_VEL, flightCapabilityEntry->MaxVel, SPELL_AURA_MOD_ADV_FLYING_MAX_VEL);
9042 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD, flightCapabilityEntry->DoubleJumpVelMod, SPELL_AURA_NONE);
9048 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION, flightCapabilityEntry->SurfaceFriction, SPELL_AURA_NONE);
9053 default:
9054 return std::tuple<OpcodeServer, float, AuraType>();
9055 }
9056 }();
9057
9058 if (rateAura != SPELL_AURA_NONE)
9059 {
9060 // take only lowest negative and highest positive auras - these effects do not stack
9061 if (float neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
9062 ApplyPct(newValue, neg);
9063
9064 if (float pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
9065 ApplyPct(newValue, pos);
9066 }
9067
9068 if (m_advFlyingSpeed[speedType] == newValue)
9069 return;
9070
9071 m_advFlyingSpeed[speedType] = newValue;
9072
9073 if (!clientUpdate)
9074 return;
9075
9076 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
9077 {
9079 selfpacket.MoverGUID = GetGUID();
9080 selfpacket.SequenceIndex = m_movementCounter++;
9081 selfpacket.Speed = newValue;
9082 playerMover->GetSession()->SendPacket(selfpacket.Write());
9083 }
9084}
9085
9086void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeRange speedType, bool clientUpdate)
9087{
9088 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
9089 if (!flightCapabilityEntry)
9090 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
9091
9092 auto [opcode, min, max, rateAura] = [&]
9093 {
9094 switch (speedType)
9095 {
9097 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE, flightCapabilityEntry->BankingRateMin, flightCapabilityEntry->BankingRateMax, SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE);
9101 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP, flightCapabilityEntry->PitchingRateUpMin, flightCapabilityEntry->PitchingRateUpMax, SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP);
9103 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD, flightCapabilityEntry->TurnVelocityThresholdMin, flightCapabilityEntry->TurnVelocityThresholdMax, SPELL_AURA_NONE);
9104 default:
9105 return std::tuple<OpcodeServer, float, float, AuraType>();
9106 }
9107 }();
9108
9109 if (rateAura != SPELL_AURA_NONE)
9110 {
9111 // take only lowest negative and highest positive auras - these effects do not stack
9112 if (float neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
9113 {
9114 ApplyPct(min, neg);
9115 ApplyPct(max, neg);
9116 }
9117
9118 if (float pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
9119 {
9120 ApplyPct(min, pos);
9121 ApplyPct(max, pos);
9122 }
9123 }
9124
9125 if (m_advFlyingSpeed[speedType] == min && m_advFlyingSpeed[speedType + 1] == max)
9126 return;
9127
9128 m_advFlyingSpeed[speedType] = min;
9129 m_advFlyingSpeed[speedType + 1] = max;
9130
9131 if (!clientUpdate)
9132 return;
9133
9134 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
9135 {
9137 selfpacket.MoverGUID = GetGUID();
9138 selfpacket.SequenceIndex = m_movementCounter++;
9139 selfpacket.SpeedMin = min;
9140 selfpacket.SpeedMax = max;
9141 playerMover->GetSession()->SendPacket(selfpacket.Write());
9142 }
9143}
9144
9146{
9147 m_followingMe.insert(f);
9148}
9149
9151{
9152 m_followingMe.erase(f);
9153}
9154
9156{
9157 while (!m_followingMe.empty())
9158 (*m_followingMe.begin())->SetTarget(nullptr);
9159}
9160
9162{
9163 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
9164 m_deathState = s;
9165
9166 bool isOnVehicle = GetVehicle() != nullptr;
9167
9168 if (s != ALIVE && s != JUST_RESPAWNED)
9169 {
9170 CombatStop();
9171
9172 if (IsNonMeleeSpellCast(false))
9174
9175 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
9176 // vehicles use special type of charm that is not removed by the next function
9177 // triggering an assert
9181 }
9182
9183 if (s == JUST_DIED)
9184 {
9185 // remove aurastates allowing special moves
9188
9189 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
9190 if (!isOnVehicle)
9191 {
9192 if (GetMotionMaster()->StopOnDeath())
9193 DisableSpline();
9194 }
9195
9196 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
9197 // do not why since in IncreaseMaxHealth currenthealth is checked
9198 SetHealth(0);
9199 SetPower(GetPowerType(), 0);
9202
9203 if (m_vignette && !m_vignette->Data->GetFlags().HasFlag(VignetteFlags::PersistsThroughDeath))
9204 SetVignette(0);
9205
9206 // players in instance don't have ZoneScript, but they have InstanceScript
9207 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
9208 zoneScript->OnUnitDeath(this);
9209 }
9210 else if (s == JUST_RESPAWNED)
9211 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
9212}
9213
9214//======================================================================
9215
9217{
9218 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
9219 {
9220 AuraApplication* aurApp = itr->second;
9221 ++itr;
9222
9223 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, true);
9224 }
9225
9227 if (spell->getState() == SPELL_STATE_PREPARING
9228 && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_IN_COMBAT_ONLY_PEACEFUL)
9229 && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Combat)
9230 && !spell->m_spellInfo->HasAura(SPELL_AURA_MOUNTED)) // for some reason mounts are not interrupted by entering combat even with both interrupt flag and attribute
9232
9235
9238}
9239
9241{
9242 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
9243 {
9244 AuraApplication* aurApp = itr->second;
9245 ++itr;
9246
9247 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, false);
9248 }
9249
9251
9254}
9255
9256void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
9257{
9258 if (!target->IsEngaged() && !canInitialAggro)
9259 return;
9260 target->EngageWithTarget(this);
9261 if (Unit* targetOwner = target->GetCharmerOrOwner())
9262 targetOwner->EngageWithTarget(this);
9263
9265 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
9266 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
9267 {
9268 myPlayerOwner->UpdatePvP(true);
9269 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
9271 }
9272}
9273
9275{
9276 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
9277
9278 bool state = false;
9279 for (Unit* minion : m_Controlled)
9280 if (minion->IsInCombat())
9281 {
9282 state = true;
9283 break;
9284 }
9285
9286 if (state)
9288 else
9290}
9291
9292void Unit::SetInteractionAllowedWhileHostile(bool interactionAllowed)
9293{
9294 if (interactionAllowed)
9296 else
9298
9300}
9301
9312
9320
9321//======================================================================
9322
9324{
9325 DiminishingReturn const& diminish = m_Diminishing[group];
9326 if (!diminish.hitCount)
9327 return DIMINISHING_LEVEL_1;
9328
9329 // If last spell was cast more than 18 seconds ago - reset level.
9330 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 18 * IN_MILLISECONDS)
9331 return DIMINISHING_LEVEL_1;
9332
9333 return DiminishingLevels(diminish.hitCount);
9334}
9335
9336void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo)
9337{
9339 uint32 currentLevel = GetDiminishing(group);
9340 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel();
9341
9342 DiminishingReturn& diminish = m_Diminishing[group];
9343 if (currentLevel < maxLevel)
9344 diminish.hitCount = currentLevel + 1;
9345}
9346
9347bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
9348{
9349 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
9350 if (duration == -1 || group == DIMINISHING_NONE)
9351 return true;
9352
9353 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration();
9354
9355 // test pet/charm masters instead pets/charmeds
9356 Unit const* targetOwner = GetCharmerOrOwner();
9357 Unit const* casterOwner = caster->GetCharmerOrOwner();
9358
9359 if (limitDuration > 0 && duration > limitDuration)
9360 {
9361 Unit const* target = targetOwner ? targetOwner : this;
9362 WorldObject const* source = casterOwner ? casterOwner : caster;
9363
9364 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
9365 duration = limitDuration;
9366 }
9367
9368 float mod = 1.0f;
9369 switch (group)
9370 {
9371 case DIMINISHING_TAUNT:
9372 {
9373 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
9374 {
9375 DiminishingLevels diminish = previousLevel;
9376 switch (diminish)
9377 {
9378 case DIMINISHING_LEVEL_1: break;
9379 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
9380 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
9381 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
9382 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
9383 default: break;
9384 }
9385 }
9386 break;
9387 }
9389 {
9390 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9391 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9392 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9393 {
9394 DiminishingLevels diminish = previousLevel;
9395 switch (diminish)
9396 {
9397 case DIMINISHING_LEVEL_1: break;
9398 case DIMINISHING_LEVEL_2: mod = 0.0f; break;
9399 default: break;
9400 }
9401 }
9402 break;
9403 }
9404 default:
9405 {
9406 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9407 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9408 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9409 {
9410 DiminishingLevels diminish = previousLevel;
9411 switch (diminish)
9412 {
9413 case DIMINISHING_LEVEL_1: break;
9414 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
9415 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
9416 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
9417 default: break;
9418 }
9419 }
9420 break;
9421 }
9422 }
9423
9424 duration = int32(duration * mod);
9425 return (duration != 0);
9426}
9427
9429{
9430 // Checking for existing in the table
9431 DiminishingReturn& diminish = m_Diminishing[group];
9432
9433 if (apply)
9434 ++diminish.stack;
9435 else if (diminish.stack)
9436 {
9437 --diminish.stack;
9438
9439 // Remember time after last aura from group removed
9440 if (!diminish.stack)
9441 diminish.hitTime = GameTime::GetGameTimeMS();
9442 }
9443}
9444
9446{
9447 for (DiminishingReturn& dim : m_Diminishing)
9448 dim.Clear();
9449}
9450
9452{
9453 if (GetTypeId() == TYPEID_PLAYER)
9454 {
9456 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
9457 if (ssEntry && ssEntry->CreatureType > 0)
9458 return ssEntry->CreatureType;
9459 else
9460 {
9461 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
9462 return raceEntry->CreatureType;
9463 }
9464 }
9465 else
9466 return ToCreature()->GetCreatureTemplate()->type;
9467}
9468
9470{
9471 uint32 creatureType = GetCreatureType();
9472 return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0;
9473}
9474
9476{
9477 uint8 creatureType = [&]() -> uint8
9478 {
9479 if (Creature const* creature = ToCreature())
9480 return creature->GetCreatureTemplate()->type;
9481
9483 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
9484 if (ssEntry && ssEntry->CreatureType > 0)
9485 return ssEntry->CreatureType;
9486
9487 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
9488 return raceEntry->CreatureType;
9489 }();
9490
9492}
9493
9499
9500void Unit::CancelShapeshiftForm(bool onlyTravelShapeshiftForm /*= false*/, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool force /*= false*/)
9501{
9503 if (form == FORM_NONE)
9504 return;
9505
9506 bool isTravelShapeshiftForm = [form]()
9507 {
9508 if (SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form))
9509 {
9510 if (shapeInfo->MountTypeID)
9511 return true;
9512
9513 if (shapeInfo->ID == FORM_TRAVEL_FORM || shapeInfo->ID == FORM_AQUATIC_FORM)
9514 return true;
9515 }
9516
9517 return false;
9518 }();
9519
9520 if (onlyTravelShapeshiftForm && !isTravelShapeshiftForm)
9521 return;
9522
9524 for (AuraEffect* aurEff : shapeshifts)
9525 {
9526 SpellInfo const* spellInfo = aurEff->GetBase()->GetSpellInfo();
9527 if (force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive()))
9528 aurEff->GetBase()->Remove(removeMode);
9529 }
9530}
9531
9533{
9535 return form == FORM_CAT_FORM || form == FORM_BEAR_FORM || form == FORM_DIRE_BEAR_FORM || form == FORM_GHOST_WOLF;
9536}
9537
9542
9543bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
9544{
9545 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
9546 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_ALLOW_WHILE_MOUNTED))
9547 return false;
9548
9549 if (form)
9550 {
9551 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
9552 if (!shapeshift)
9553 return true;
9554
9555 if (!shapeshift->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance))
9556 return true;
9557 }
9558
9559 if (displayId == GetNativeDisplayId())
9560 return false;
9561
9562 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(displayId);
9563 if (!display)
9564 return true;
9565
9567 if (!displayExtra)
9568 return true;
9569
9570 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
9571 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
9572
9574 if (race && !race->GetFlags().HasFlag(ChrRacesFlag::CanMount))
9575 return true;
9576
9577 return false;
9578}
9579
9580/*#######################################
9581######## ########
9582######## STAT SYSTEM ########
9583######## ########
9584#######################################*/
9585
9586void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
9587{
9588 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9589 {
9590 TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!");
9591 return;
9592 }
9593
9594 if (!amount)
9595 return;
9596
9597 switch (modifierType)
9598 {
9599 case BASE_VALUE:
9601 case TOTAL_VALUE:
9602 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9603 break;
9604 default:
9605 break;
9606 }
9607
9608 UpdateUnitMod(unitMod);
9609}
9610
9611void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
9612{
9613 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9614 {
9615 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
9616 return;
9617 }
9618
9619 if (!pct)
9620 return;
9621
9622 switch (modifierType)
9623 {
9624 case BASE_PCT:
9625 case TOTAL_PCT:
9626 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9627 break;
9628 default:
9629 break;
9630 }
9631
9632 UpdateUnitMod(unitMod);
9633}
9634
9635void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9636{
9637 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9638 return;
9639
9640 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9641 UpdateUnitMod(unitMod);
9642}
9643
9644void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9645{
9646 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9647 return;
9648
9649 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9650 UpdateUnitMod(unitMod);
9651}
9652
9654{
9655 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9656 {
9657 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9658 return 0.0f;
9659 }
9660
9661 return m_auraFlatModifiersGroup[unitMod][modifierType];
9662}
9663
9665{
9666 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9667 {
9668 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9669 return 0.0f;
9670 }
9671
9672 return m_auraPctModifiersGroup[unitMod][modifierType];
9673}
9674
9676{
9677 if (!CanModifyStats())
9678 return;
9679
9680 switch (unitMod)
9681 {
9687
9688 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9689 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9690
9691 case UNIT_MOD_MANA:
9692 case UNIT_MOD_RAGE:
9693 case UNIT_MOD_FOCUS:
9694 case UNIT_MOD_ENERGY:
9696 case UNIT_MOD_RUNES:
9701 case UNIT_MOD_ALTERNATE:
9702 case UNIT_MOD_MAELSTROM:
9703 case UNIT_MOD_CHI:
9704 case UNIT_MOD_INSANITY:
9708 case UNIT_MOD_FURY:
9709 case UNIT_MOD_PAIN:
9710 case UNIT_MOD_ESSENCE:
9717
9724
9727
9731
9732 default:
9733 ABORT_MSG("Not implemented UnitMod %u", unitMod);
9734 break;
9735 }
9736}
9737
9738void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9739{
9740 UnitMods unitMod;
9741 switch (attackType)
9742 {
9743 case BASE_ATTACK:
9744 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9745 break;
9746 case OFF_ATTACK:
9747 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9748 break;
9749 case RANGED_ATTACK:
9750 unitMod = UNIT_MOD_DAMAGE_RANGED;
9751 break;
9752 default:
9753 ABORT();
9754 break;
9755 }
9756
9757 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9758 {
9759 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9760 return false;
9761
9762 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9763 });
9764
9765 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9766}
9767
9773
9775{
9776 float factor;
9777 UnitMods unitMod;
9778 switch (attackType)
9779 {
9780 case BASE_ATTACK:
9781 factor = 1.0f;
9782 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9783 break;
9784 case OFF_ATTACK:
9785 // off hand has 50% penalty
9786 factor = 0.5f;
9787 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9788 break;
9789 case RANGED_ATTACK:
9790 factor = 1.0f;
9791 unitMod = UNIT_MOD_DAMAGE_RANGED;
9792 break;
9793 default:
9794 ABORT();
9795 break;
9796 }
9797
9798 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9799 {
9800 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9801 return false;
9802
9803 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9804 });
9805
9806 if (attackType == OFF_ATTACK)
9807 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, [this, attackType](AuraEffect const* aurEff)
9808 {
9809 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9810 });
9811
9812 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9813}
9814
9820
9822{
9823 float createStat = GetCreateStat(stat); // retrieved early to workaround a GCC false positive warning about out of bounds array access (conversion to UnitMods confuses it)
9824
9826
9827 // value = ((base_value * base_pct) + total_value) * total_pct
9828 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9829 value += createStat;
9830 value *= GetPctModifierValue(unitMod, BASE_PCT);
9831 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9832 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9833
9834 return value;
9835}
9836
9838{
9839 if (unitMod >= UNIT_MOD_END)
9840 {
9841 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9842 return 0.0f;
9843 }
9844
9845 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9846 value *= GetPctModifierValue(unitMod, BASE_PCT);
9847 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9848 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9849
9850 return value;
9851}
9852
9854{
9856
9857 switch (unitMod)
9858 {
9859 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9860 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9861 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9862 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9863 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9864 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9865
9866 default:
9867 break;
9868 }
9869
9870 return school;
9871}
9872
9874{
9875 Stats stat = STAT_STRENGTH;
9876
9877 switch (unitMod)
9878 {
9879 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9880 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9881 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9882 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9883 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
9884 default:
9885 break;
9886 }
9887
9888 return stat;
9889}
9890
9892{
9893 if (school > SPELL_SCHOOL_NORMAL)
9894 {
9895 UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
9896
9897 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9898 value *= GetPctModifierValue(unitMod, BASE_PCT);
9899
9900 float baseValue = value;
9901
9902 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9903 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9904
9905 SetResistance(SpellSchools(school), int32(value));
9906 SetBonusResistanceMod(SpellSchools(school), int32(value - baseValue));
9907 }
9908 else
9909 UpdateArmor();
9910}
9911
9912float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon /*= true*/) const
9913{
9914 if (attType == RANGED_ATTACK)
9915 {
9916 float ap = m_unitData->RangedAttackPower + m_unitData->RangedAttackPowerModPos + m_unitData->RangedAttackPowerModNeg;
9917 if (includeWeapon)
9918 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9919 if (ap < 0)
9920 return 0.0f;
9921 return ap * (1.0f + m_unitData->RangedAttackPowerMultiplier);
9922 }
9923 else
9924 {
9925 float ap = m_unitData->AttackPower + m_unitData->AttackPowerModPos + m_unitData->AttackPowerModNeg;
9926 if (includeWeapon)
9927 {
9928 if (attType == BASE_ATTACK)
9929 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9930 else
9931 {
9932 ap += m_unitData->OffHandWeaponAttackPower;
9933 ap /= 2;
9934 }
9935 }
9936 if (ap < 0)
9937 return 0.0f;
9938 return ap * (1.0f + m_unitData->AttackPowerMultiplier);
9939 }
9940}
9941
9943{
9944 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9945 return 0.0f;
9946
9947 return m_weaponDamage[attType][type];
9948}
9949
9955
9956void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
9957{
9959
9960 if (!sendUpdate)
9961 return;
9962
9963 if (Player* player = ToPlayer())
9964 {
9965 // group update
9966 if (player->GetGroup())
9967 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9968
9969 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
9970 }
9971}
9972
9974{
9976 val = 0;
9977 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
9978 val = 1;
9979 else
9980 {
9981 uint64 maxHealth = GetMaxHealth();
9982 if (maxHealth < val)
9983 val = maxHealth;
9984 }
9985
9986 uint64 oldVal = GetHealth();
9988
9989 TriggerOnHealthChangeAuras(oldVal, val);
9990
9991 // group update
9992 if (Player* player = ToPlayer())
9993 {
9994 if (player->GetGroup())
9995 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9996 }
9997 else if (Pet* pet = ToCreature()->ToPet())
9998 {
9999 if (pet->isControlled())
10000 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
10001 }
10002}
10003
10005{
10006 if (!val)
10007 val = 1;
10008
10009 uint64 health = GetHealth();
10011
10012 // group update
10013 if (GetTypeId() == TYPEID_PLAYER)
10014 {
10015 if (ToPlayer()->GetGroup())
10017 }
10018 else if (Pet* pet = ToCreature()->ToPet())
10019 {
10020 if (pet->isControlled())
10021 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
10022 }
10023
10024 if (val < health)
10025 SetHealth(val);
10026}
10027
10029{
10030 uint32 powerIndex = GetPowerIndex(power);
10031 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
10032 return 0;
10033
10034 return m_unitData->Power[powerIndex];
10035}
10036
10038{
10039 uint32 powerIndex = GetPowerIndex(power);
10040 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
10041 return 0;
10042
10043 return m_unitData->MaxPower[powerIndex];
10044}
10045
10046void Unit::SetPower(Powers power, int32 val, bool withPowerUpdate /*= true*/)
10047{
10048 uint32 powerIndex = GetPowerIndex(power);
10049 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
10050 return;
10051
10052 int32 maxPower = GetMaxPower(power);
10053 if (maxPower < val)
10054 val = maxPower;
10055
10056 int32 oldPower = m_unitData->Power[powerIndex];
10058
10059 if (IsInWorld() && withPowerUpdate)
10060 {
10062 packet.Guid = GetGUID();
10064 packet.Powers.emplace_back(val, power);
10066 }
10067
10068 TriggerOnPowerChangeAuras(power, oldPower, val);
10069
10070 // group update
10071 if (Player* player = ToPlayer())
10072 {
10073 if (player->GetGroup())
10074 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
10075 }
10076 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
10077 {
10078 if (pet->isControlled())
10079 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
10080 }*/
10081}
10082
10084{
10085 uint32 powerIndex = GetPowerIndex(power);
10086 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
10087 return;
10088
10089 int32 cur_power = GetPower(power);
10091
10092 // group update
10093 if (GetTypeId() == TYPEID_PLAYER)
10094 {
10095 if (ToPlayer()->GetGroup())
10097 }
10098 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
10099 {
10100 if (pet->isControlled())
10101 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
10102 }*/
10103
10104 if (val < cur_power)
10105 SetPower(power, val);
10106}
10107
10109{
10110 auto processAuras = [&](AuraEffectVector const& effects)
10111 {
10112 for (AuraEffect const* effect : effects)
10113 {
10114 if (effect->GetMiscValue() == power)
10115 {
10116 SpellEffectValue effectAmount = effect->GetAmount();
10117 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
10118
10119 SpellEffectValue oldValueCheck = oldVal;
10120 SpellEffectValue newValueCheck = newVal;
10121
10122 if (effect->GetAuraType() == SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT)
10123 {
10124 int32 maxPower = GetMaxPower(power);
10125 if (!maxPower)
10126 continue;
10127
10128 oldValueCheck = GetPctOf(oldVal, maxPower);
10129 newValueCheck = GetPctOf(newVal, maxPower);
10130 }
10131
10132 switch (AuraTriggerOnPowerChangeDirection(effect->GetMiscValueB()))
10133 {
10135 if (oldValueCheck >= effect->GetAmount() || newValueCheck < effectAmount)
10136 continue;
10137 break;
10139 if (oldValueCheck <= effect->GetAmount() || newValueCheck > effectAmount)
10140 continue;
10141 break;
10142 default:
10143 break;
10144 }
10145
10146 CastSpell(this, triggerSpell, effect);
10147 }
10148 }
10149 };
10150
10153}
10154
10156{
10157 if (UnitAI* ai = GetAI())
10158 {
10159 m_aiLocked = true;
10160 ai->UpdateAI(diff);
10161 m_aiLocked = false;
10162 }
10163}
10164
10166{
10167 i_AIs.emplace(newAI);
10168}
10169
10171{
10172 PushAI(newAI);
10173 RefreshAI();
10174}
10175
10177{
10178 if (!i_AIs.empty())
10179 {
10180 i_AIs.pop();
10181 return true;
10182 }
10183 else
10184 return false;
10185}
10186
10188{
10189 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
10190 if (i_AIs.empty())
10191 i_AI = nullptr;
10192 else
10193 i_AI = i_AIs.top();
10194}
10195
10197{
10198 bool const charmed = IsCharmed();
10199
10200 if (charmed)
10202 else
10203 {
10205 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
10206 }
10207}
10208
10210{
10211 // Keep popping the stack until we either reach the bottom or find a valid AI
10212 while (PopAI())
10213 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
10214 return;
10215}
10216
10218{
10219 if (Creature* creature = ToCreature())
10220 return sCreatureAIRegistry->GetRegistryItem("ScheduledChangeAI")->Create(creature);
10221 else
10222 return nullptr;
10223}
10224
10226{
10227 if (UnitAI* ai = GetAI())
10228 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
10229 else
10230 return true;
10231}
10232
10240
10242{
10243 // cleanup
10244 ASSERT(GetGUID());
10245
10246 if (IsInWorld())
10247 {
10248 if (IsAreaSpiritHealer())
10249 {
10250 if (Creature* creature = ToCreature())
10251 creature->SummonGraveyardTeleporter();
10252 }
10253
10255 if (UnitAI* ai = GetAI())
10256 ai->OnDespawn();
10257
10258 if (IsVehicle())
10259 RemoveVehicleKit(true);
10260
10265
10269 ExitAllAreaTriggers(); // exit all areatriggers the unit is in
10270
10271 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
10274
10276
10278
10279 if (IsCharmed())
10280 RemoveCharmedBy(nullptr);
10281
10282 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
10283 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
10284
10285 if (Unit* owner = GetOwner())
10286 {
10287 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
10288 {
10289 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
10290 ABORT();
10291 }
10292 }
10293
10296 }
10297}
10298
10300{
10301 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
10303
10304 SetVignette(0);
10305
10306 if (IsInWorld())
10308 else
10309 {
10310 // cleanup that must happen even if not in world
10311 if (IsVehicle())
10312 RemoveVehicleKit(true);
10313 }
10314
10315 ASSERT(GetGUID());
10316
10317 // A unit may be in removelist and not in world, but it is still in grid
10318 // and may have some references during delete
10321
10322 if (finalCleanup)
10323 m_cleanupDone = true;
10324
10325 CombatStop();
10326}
10327
10328void Unit::CleanupsBeforeDelete(bool finalCleanup)
10329{
10330 CleanupBeforeRemoveFromMap(finalCleanup);
10331
10333}
10334
10336{
10337 if (IsCharmed())
10338 {
10339 UnitAI* newAI = nullptr;
10340 if (GetTypeId() == TYPEID_PLAYER)
10341 {
10342 if (Unit* charmer = GetCharmer())
10343 {
10344 // first, we check if the creature's own AI specifies an override playerai for its owned players
10345 if (Creature* creatureCharmer = charmer->ToCreature())
10346 {
10347 if (CreatureAI* charmerAI = creatureCharmer->AI())
10348 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
10349 }
10350 else
10351 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
10352 }
10353 if (!newAI) // otherwise, we default to the generic one
10354 newAI = new SimpleCharmedPlayerAI(ToPlayer());
10355 }
10356 else
10357 {
10359 if (isPossessed() || IsVehicle())
10360 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature());
10361 else
10362 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature());
10363 }
10364
10365 ASSERT(newAI);
10366 SetAI(newAI);
10367 newAI->OnCharmed(true);
10368 }
10369 else
10370 {
10372 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
10373 RefreshAI();
10374 if (UnitAI* ai = GetAI())
10375 ai->OnCharmed(true);
10376 }
10377}
10378
10380{
10381 if (!m_charmInfo)
10382 m_charmInfo = std::make_unique<CharmInfo>(this);
10383
10384 return m_charmInfo.get();
10385}
10386
10388{
10389 if (!m_charmInfo)
10390 return;
10391
10392 m_charmInfo->RestoreState();
10393 m_charmInfo = nullptr;
10394}
10395
10397{
10401
10403 packet.MoverGUID = target->GetGUID();
10404 ToPlayer()->SendDirectMessage(packet.Write());
10405}
10406
10408{
10409 ProcFlagsHit hitMask = PROC_HIT_NONE;
10410 // Check victim state
10411 if (missCondition != SPELL_MISS_NONE)
10412 {
10413 switch (missCondition)
10414 {
10415 case SPELL_MISS_MISS:
10416 hitMask |= PROC_HIT_MISS;
10417 break;
10418 case SPELL_MISS_DODGE:
10419 hitMask |= PROC_HIT_DODGE;
10420 break;
10421 case SPELL_MISS_PARRY:
10422 hitMask |= PROC_HIT_PARRY;
10423 break;
10424 case SPELL_MISS_BLOCK:
10425 // spells can't be partially blocked (it's damage can though)
10427 break;
10428 case SPELL_MISS_EVADE:
10429 hitMask |= PROC_HIT_EVADE;
10430 break;
10431 case SPELL_MISS_IMMUNE:
10432 case SPELL_MISS_IMMUNE2:
10433 hitMask |= PROC_HIT_IMMUNE;
10434 break;
10435 case SPELL_MISS_DEFLECT:
10436 hitMask |= PROC_HIT_DEFLECT;
10437 break;
10438 case SPELL_MISS_ABSORB:
10439 hitMask |= PROC_HIT_ABSORB;
10440 break;
10441 case SPELL_MISS_REFLECT:
10442 hitMask |= PROC_HIT_REFLECT;
10443 break;
10444 case SPELL_MISS_RESIST:
10445 hitMask |= PROC_HIT_FULL_RESIST;
10446 break;
10447 default:
10448 break;
10449 }
10450 }
10451 else
10452 {
10453 // On block
10454 if (damageInfo->blocked)
10455 {
10456 hitMask |= PROC_HIT_BLOCK;
10457 if (damageInfo->fullBlock)
10458 hitMask |= PROC_HIT_FULL_BLOCK;
10459 }
10460 // On absorb
10461 if (damageInfo->absorb)
10462 hitMask |= PROC_HIT_ABSORB;
10463
10464 // Don't set hit/crit hitMask if damage is nullified
10465 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
10466 if (!damageNullified)
10467 {
10468 // On crit
10469 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10470 hitMask |= PROC_HIT_CRITICAL;
10471 else
10472 hitMask |= PROC_HIT_NORMAL;
10473 }
10474 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
10475 hitMask |= PROC_HIT_FULL_RESIST;
10476 }
10477
10478 return hitMask;
10479}
10480
10481void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, ProcFlagsInit const& typeMask, ProcFlagsHit hitMask, WeaponAttackType /*attType*/)
10482{
10483 // Player is loaded now - do not allow passive spell casts to proc
10484 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
10485 return;
10486
10487 // For melee/ranged based attack need update skills and set some Aura states if victim present
10488 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
10489 {
10490 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10492 {
10493 // for victim
10494 if (isVictim)
10495 {
10496 // if victim and dodge attack
10497 if (hitMask & PROC_HIT_DODGE)
10498 {
10499 // Update AURA_STATE on dodge
10500 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
10501 {
10504 }
10505 }
10506 // if victim and parry attack
10507 if (hitMask & PROC_HIT_PARRY)
10508 {
10511 }
10512 // if and victim block attack
10513 if (hitMask & PROC_HIT_BLOCK)
10514 {
10517 }
10518 }
10519 }
10520 }
10521}
10522
10524{
10525 TimePoint now = GameTime::Now();
10526
10527 auto processAuraApplication = [&](AuraApplication* aurApp)
10528 {
10529 if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
10530 {
10531 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
10532 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
10533 }
10534 else
10535 {
10537 {
10538 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10539 {
10540 aurApp->GetBase()->PrepareProcChargeDrop(procEntry, eventInfo);
10541 aurasTriggeringProc.emplace_back(0, aurApp);
10542 }
10543 }
10544
10546 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10547 aurApp->GetBase()->AddProcCooldown(procEntry, now);
10548 }
10549 };
10550
10551 // use provided list of auras which can proc
10552 if (procAuras)
10553 {
10554 for (AuraApplication* aurApp : *procAuras)
10555 {
10556 ASSERT(aurApp->GetTarget() == this);
10557 processAuraApplication(aurApp);
10558 }
10559 }
10560 // or generate one on our own
10561 else
10562 {
10563 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
10564 processAuraApplication(itr->second);
10565 }
10566}
10567
10568void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras, Unit* actionTarget,
10569 ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget, ProcFlagsSpellType spellTypeMask,
10570 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
10571{
10572 // prepare data for self trigger
10573 ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10574 AuraApplicationProcContainer myAurasTriggeringProc;
10575 if (typeMaskActor)
10576 {
10577 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
10578
10579 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
10580 if (Player* modOwner = GetSpellModOwner())
10581 {
10582 if (modOwner != this && spell)
10583 {
10584 AuraApplicationList modAuras;
10585 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
10586 {
10587 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
10588 modAuras.push_front(itr->second);
10589 }
10590 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
10591 }
10592 }
10593 }
10594
10595 // prepare data for target trigger
10596 ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10597 AuraApplicationProcContainer targetAurasTriggeringProc;
10598 if (typeMaskActionTarget && actionTarget)
10599 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
10600
10601 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
10602
10603 if (typeMaskActionTarget && actionTarget)
10604 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
10605}
10606
10608{
10609 Spell const* triggeringSpell = eventInfo.GetProcSpell();
10610 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
10611
10612 int32 oldProcChainLength = std::exchange(m_procChainLength, std::max(m_procChainLength + 1, triggeringSpell ? triggeringSpell->GetProcChainLength() : 0));
10613
10614 if (disableProcs)
10615 SetCantProc(true);
10616
10617 for (auto const& [procEffectMask, aurApp] : aurasTriggeringProc)
10618 {
10619 if (aurApp->GetRemoveMode())
10620 continue;
10621
10622 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
10623 }
10624
10625 if (disableProcs)
10626 SetCantProc(false);
10627
10628 m_procChainLength = oldProcChainLength;
10629}
10630
10633{
10634 Unit* owner = GetOwner();
10635 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10636 return;
10637
10638 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10639 petActionFeedback.SpellID = spellId;
10640 petActionFeedback.Response = msg;
10641 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10642}
10643
10645{
10646 Unit* owner = GetOwner();
10647 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10648 return;
10649
10650 WorldPackets::Pet::PetActionSound petActionSound;
10651 petActionSound.UnitGUID = GetGUID();
10652 petActionSound.Action = pettalk;
10653 owner->ToPlayer()->SendDirectMessage(petActionSound.Write());
10654}
10655
10657{
10658 Unit* owner = GetOwner();
10659 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10660 return;
10661
10663 packet.UnitGUID = guid;
10665 owner->ToPlayer()->SendDirectMessage(packet.Write());
10666}
10667
10669
10674
10679
10681{
10683
10684 // not need send any packets if not in world or not moving
10685 if (!IsInWorld() || movespline->Finalized())
10686 return;
10687
10688 // Update position now since Stop does not start a new movement that can be updated later
10689 if (movespline->HasStarted())
10691 Movement::MoveSplineInit init(this);
10692 init.Stop();
10693}
10694
10695void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10696{
10697 if (IsInvalidMovementSlot(slot))
10698 return;
10699
10700 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10701 movementGenerator->Pause(timer);
10702
10703 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10704 StopMoving();
10705}
10706
10707void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10708{
10709 if (IsInvalidMovementSlot(slot))
10710 return;
10711
10712 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10713 movementGenerator->Resume(timer);
10714}
10715
10724
10726{
10729}
10730
10731void Unit::SetStandState(UnitStandStateType state, uint32 animKitID /* = 0*/)
10732{
10734
10735 if (IsStandState())
10737
10738 if (GetTypeId() == TYPEID_PLAYER)
10739 {
10740 WorldPackets::Misc::StandStateUpdate packet(state, animKitID);
10741 ToPlayer()->SendDirectMessage(packet.Write());
10742 }
10743}
10744
10745void Unit::SetAnimTier(AnimTier animTier, bool notifyClient /*= true*/)
10746{
10748
10749 if (notifyClient)
10750 {
10752 setAnimTier.Unit = GetGUID();
10753 setAnimTier.Tier = AsUnderlyingType(animTier);
10754 SendMessageToSet(setAnimTier.Write(), true);
10755 }
10756}
10757
10759{
10760 uint32 transformId = GetTransformSpell();
10761 if (!transformId)
10762 return false;
10763
10764 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId, GetMap()->GetDifficultyID());
10765 if (!spellInfo)
10766 return false;
10767
10768 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10769}
10770
10772{
10774 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10775 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1f : 0.01f;
10776 SetObjectScale(std::max(scale, scaleMin));
10777}
10778
10779void Unit::SetDisplayId(uint32 displayId, bool setNative /*= false*/)
10780{
10781 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
10782
10783 if (IsCreature() && !IsPet())
10784 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
10785 displayScale = model->DisplayScale;
10786
10789
10790 if (setNative)
10791 {
10794 }
10795
10796 // Set Gender by ModelInfo
10797 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(displayId))
10798 SetGender(Gender(modelInfo->gender));
10799
10801}
10802
10803void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false*/)
10804{
10805 AuraEffect* handledAura = nullptr;
10806 // try to receive model from transform auras
10808 if (!transforms.empty())
10809 {
10810 // iterate over already applied transform auras - from newest to oldest
10811 for (auto i = transforms.begin(); i != transforms.end(); ++i)
10812 {
10813 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10814 {
10815 if (!handledAura)
10816 {
10817 if (!ignorePositiveAurasPreventingMounting)
10818 handledAura = (*i);
10819 else if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*i)->GetMiscValue()))
10821 handledAura = (*i);
10822 }
10823 // prefer negative auras
10824 if (!aurApp->IsPositive())
10825 {
10826 handledAura = (*i);
10827 break;
10828 }
10829 }
10830 }
10831 }
10832
10834
10835 // transform aura was found
10836 if (handledAura)
10837 {
10838 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10839 return;
10840 }
10841 // we've found shapeshift
10842 else if (!shapeshiftAura.empty()) // we've found shapeshift
10843 {
10844 // only one such aura possible at a time
10845 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10846 {
10847 if (!ignorePositiveAurasPreventingMounting || !IsDisallowedMountForm(0, GetShapeshiftForm(), modelId))
10848 SetDisplayId(modelId);
10849 else
10851 return;
10852 }
10853 }
10854 // no auras found - set modelid to default
10856}
10857
10859{
10860 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10861 m_reactiveTimer[i] = 0;
10862
10867}
10868
10870{
10871 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10872 {
10873 ReactiveType reactive = ReactiveType(i);
10874
10875 if (!m_reactiveTimer[reactive])
10876 continue;
10877
10878 if (m_reactiveTimer[reactive] <= p_time)
10879 {
10880 m_reactiveTimer[reactive] = 0;
10881
10882 switch (reactive)
10883 {
10884 case REACTIVE_DEFENSE:
10887 break;
10888 case REACTIVE_DEFENSE_2:
10891 break;
10892 default:
10893 break;
10894 }
10895 }
10896 else
10897 {
10898 m_reactiveTimer[reactive] -= p_time;
10899 }
10900 }
10901}
10902
10903Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10904{
10905 std::list<Unit*> targets;
10906 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10908 Cell::VisitAllObjects(this, searcher, dist);
10909
10910 // remove current target
10911 if (GetVictim())
10912 targets.remove(GetVictim());
10913
10914 if (exclude)
10915 targets.remove(exclude);
10916
10917 // remove not LoS targets
10918 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10919 {
10920 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10921 targets.erase(tIter++);
10922 else
10923 ++tIter;
10924 }
10925
10926 // no appropriate targets
10927 if (targets.empty())
10928 return nullptr;
10929
10930 // select random
10932}
10933
10935{
10936 return m_baseAttackSpeed[att];
10937}
10938
10940{
10941 m_baseAttackSpeed[att] = val;
10943}
10944
10960
10961void ApplyPercentModFloatVar(float& var, float val, bool apply)
10962{
10963 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
10964}
10965
10967{
10968 float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]);
10969 if (val > 0.f)
10970 {
10972
10973 if (att == BASE_ATTACK)
10975 else if (att == RANGED_ATTACK)
10977 }
10978 else
10979 {
10981
10982 if (att == BASE_ATTACK)
10984 else if (att == RANGED_ATTACK)
10986 }
10987
10989 m_attackTimer[att] = uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att] * remainingTimePct);
10990}
10991
11007
11009{
11010 if (Player* player = ToPlayer())
11011 {
11012 if (player->GetGroup())
11013 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
11014 }
11015 else if (GetTypeId() == TYPEID_UNIT && IsPet())
11016 {
11017 Pet* pet = ((Pet*)this);
11018 if (pet->isControlled())
11020 }
11021}
11022
11023void Unit::SetCantProc(bool apply)
11024{
11025 if (apply)
11026 ++m_procDeep;
11027 else
11028 {
11030 --m_procDeep;
11031 }
11032}
11033
11034float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
11035{
11036 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
11037 return GetBaseAttackTime(attType) / 1000.0f;
11038
11039 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
11040 if (!weapon)
11041 return 2.0f;
11042
11043 if (!normalized)
11044 return weapon->GetTemplate()->GetDelay() / 1000.0f;
11045
11046 switch (weapon->GetTemplate()->GetSubClass())
11047 {
11054 return 3.3f;
11062 return 2.4f;
11064 return 1.7f;
11066 return 2.0f;
11067 default:
11068 return weapon->GetTemplate()->GetDelay() / 1000.0f;
11069 }
11070}
11071
11072Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
11073{
11074 if (GetTypeId() != TYPEID_PLAYER)
11075 return nullptr;
11076
11077 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
11078
11079 if (!pet->CreateBaseAtCreature(creatureTarget))
11080 {
11081 delete pet;
11082 return nullptr;
11083 }
11084
11085 uint8 level = creatureTarget->GetLevelForTarget(this) + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget->GetLevelForTarget(this);
11086
11087 if (!InitTamedPet(pet, level, spell_id))
11088 {
11089 delete pet;
11090 return nullptr;
11091 }
11092
11093 return pet;
11094}
11095
11097{
11098 if (GetTypeId() != TYPEID_PLAYER)
11099 return nullptr;
11100
11101 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
11102 if (!creatureInfo)
11103 return nullptr;
11104
11105 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
11106
11107 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
11108 {
11109 delete pet;
11110 return nullptr;
11111 }
11112
11113 return pet;
11114}
11115
11116bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
11117{
11118 Player* player = ToPlayer();
11119 PetStable& petStable = player->GetOrInitPetStable();
11120 auto freeActiveSlotItr = std::find_if(petStable.ActivePets.begin(), petStable.ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
11121 {
11122 return !petInfo.has_value();
11123 });
11124
11125 if (freeActiveSlotItr == petStable.ActivePets.end())
11126 return false;
11127
11128 pet->SetCreatorGUID(GetGUID());
11129 pet->SetFaction(GetFaction());
11130 pet->SetCreatedBySpell(spell_id);
11132
11133 if (!pet->InitStatsForLevel(level))
11134 {
11135 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
11136 return false;
11137 }
11138
11140
11141 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11142 // this enables pet details window (Shift+P)
11143 pet->InitPetCreateSpells();
11144 //pet->InitLevelupSpellsForLevel();
11145 pet->SetFullHealth();
11146
11147 petStable.SetCurrentActivePetIndex(std::distance(petStable.ActivePets.begin(), freeActiveSlotItr));
11148 pet->FillPetInfo(&freeActiveSlotItr->emplace());
11149 player->AddPetToUpdateFields(**freeActiveSlotItr, PetSaveMode(*petStable.GetCurrentActivePetIndex()), PET_STABLE_ACTIVE);
11150 return true;
11151}
11152
11154{
11156 packet.Percent = percent;
11157 receiver->GetSession()->SendPacket(packet.Write());
11158}
11159
11161{
11162 if (!sAnimKitStore.LookupEntry(animKitId))
11163 {
11164 TC_LOG_ERROR("entities.unit", "Unit::PlayOneShotAnimKitId using invalid AnimKit ID: {}", animKitId);
11165 return;
11166 }
11167
11169 data.Unit = GetGUID();
11170 data.AnimKitID = animKitId;
11171 SendMessageToSet(data.Write(), true);
11172}
11173
11175{
11176 if (_aiAnimKitId == animKitId)
11177 return;
11178
11179 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11180 return;
11181
11182 _aiAnimKitId = animKitId;
11184
11186 data.Unit = GetGUID();
11187 data.AnimKitID = animKitId;
11188 SendMessageToSet(data.Write(), true);
11189}
11190
11192{
11193 if (_movementAnimKitId == animKitId)
11194 return;
11195
11196 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11197 return;
11198
11199 _movementAnimKitId = animKitId;
11201
11203 data.Unit = GetGUID();
11204 data.AnimKitID = animKitId;
11205 SendMessageToSet(data.Write(), true);
11206}
11207
11209{
11210 if (_meleeAnimKitId == animKitId)
11211 return;
11212
11213 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11214 return;
11215
11216 _meleeAnimKitId = animKitId;
11218
11220 data.Unit = GetGUID();
11221 data.AnimKitID = animKitId;
11222 SendMessageToSet(data.Write(), true);
11223}
11224
11225/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/, bool skipSettingDeathState /*= false*/)
11226{
11227 // Prevent killing unit twice (and giving reward from kill twice)
11228 if (!victim->GetHealth())
11229 return;
11230
11231 if (attacker && !attacker->IsInMap(victim))
11232 attacker = nullptr;
11233
11234 // find player: owner of controlled `this` or `this` itself maybe
11235 Player* player = nullptr;
11236 if (attacker)
11237 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
11238
11239 Creature* creature = victim->ToCreature();
11240
11241 bool isRewardAllowed = attacker != victim;
11242 if (creature)
11243 isRewardAllowed = isRewardAllowed && !creature->GetTapList().empty();
11244
11245 std::vector<Player*> tappers;
11246 if (isRewardAllowed && creature)
11247 {
11248 for (ObjectGuid tapperGuid : creature->GetTapList())
11249 if (Player* tapper = ObjectAccessor::GetPlayer(*creature, tapperGuid))
11250 tappers.push_back(tapper);
11251
11252 if (!creature->CanHaveLoot())
11253 isRewardAllowed = false;
11254 }
11255
11256 // Exploit fix
11257 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
11258 isRewardAllowed = false;
11259
11260 // Reward player, his pets, and group/raid members
11261 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
11262 if (isRewardAllowed)
11263 {
11264 std::unordered_set<Group*> groups;
11265 for (Player* tapper : tappers)
11266 {
11267 if (Group* tapperGroup = tapper->GetGroup())
11268 {
11269 if (groups.insert(tapperGroup).second)
11270 {
11272 partyKillLog.Player = player && tapperGroup->IsMember(player->GetGUID()) ? player->GetGUID() : tapper->GetGUID();
11273 partyKillLog.Victim = victim->GetGUID();
11274 partyKillLog.Write();
11275
11276 tapperGroup->BroadcastPacket(partyKillLog.GetRawPacket(), tapperGroup->GetMemberGroup(tapper->GetGUID()) != 0);
11277
11278 if (creature)
11279 tapperGroup->UpdateLooterGuid(creature, true);
11280 }
11281 }
11282 else
11283 {
11285 partyKillLog.Player = tapper->GetGUID();
11286 partyKillLog.Victim = victim->GetGUID();
11287 tapper->SendDirectMessage(partyKillLog.Write());
11288 }
11289 }
11290
11291 // Generate loot before updating looter
11292 if (creature)
11293 {
11294 DungeonEncounterEntry const* dungeonEncounter = nullptr;
11295 if (InstanceScript const* instance = creature->GetInstanceScript())
11296 dungeonEncounter = instance->GetBossDungeonEncounter(creature);
11297
11298 if (creature->GetMap()->IsDungeon())
11299 {
11300 if (dungeonEncounter)
11301 {
11302 creature->m_personalLoot = GenerateDungeonEncounterPersonalLoot(dungeonEncounter->ID, creature->GetLootId(),
11304 creature->GetLootMode(), creature->GetMap()->GetMapDifficulty(), tappers);
11305 }
11306 else if (!tappers.empty())
11307 {
11308 Group* group = !groups.empty() ? *groups.begin() : nullptr;
11309 Player* looter = group ? ASSERT_NOTNULL(ObjectAccessor::GetPlayer(*creature, group->GetLooterGuid())) : tappers[0];
11310
11311 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, dungeonEncounter ? group : nullptr);
11312
11313 if (uint32 lootid = creature->GetLootId())
11314 loot->FillLoot(lootid, LootTemplates_Creature, looter, dungeonEncounter != nullptr, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), looter));
11315
11316 if (creature->GetLootMode() > 0)
11318
11319 if (group)
11320 loot->NotifyLootList(creature->GetMap());
11321
11322 creature->m_personalLoot[looter->GetGUID()].reset(loot); // trash mob loot is personal, generated with round robin rules
11323
11324 // Update round robin looter only if the creature had loot
11325 if (!loot->isLooted())
11326 for (Group* tapperGroup : groups)
11327 tapperGroup->UpdateLooterGuid(creature);
11328 }
11329 }
11330 else
11331 {
11332 for (Player* tapper : tappers)
11333 {
11334 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, nullptr);
11335
11336 if (dungeonEncounter)
11337 loot->SetDungeonEncounterId(dungeonEncounter->ID);
11338
11339 if (uint32 lootid = creature->GetLootId())
11340 loot->FillLoot(lootid, LootTemplates_Creature, tapper, true, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), tapper));
11341
11342 if (creature->GetLootMode() > 0)
11344
11345 creature->m_personalLoot[tapper->GetGUID()].reset(loot);
11346 }
11347 }
11348 }
11349
11350 if (Vignettes::VignetteData const* vignette = victim->GetVignette())
11351 {
11352 for (Player* tapper : tappers)
11353 {
11354 if (Quest const* reward = sObjectMgr->GetQuestTemplate(vignette->Data->RewardQuestID))
11355 tapper->RewardQuest(reward, LootItemType::Item, 0, victim, false);
11356
11357 if (vignette->Data->VisibleTrackingQuestID)
11358 tapper->SetRewardedQuest(vignette->Data->VisibleTrackingQuestID);
11359 }
11360 }
11361
11362 KillRewarder(Trinity::IteratorPair(tappers.data(), tappers.data() + tappers.size()), victim, false).Reward();
11363 }
11364
11365 // 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
11366 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
11367 {
11368 // proc only once for victim
11369 if (Unit* owner = attacker->GetOwner())
11371 }
11372
11373 if (!victim->IsCritter())
11374 {
11376
11377 for (Player* tapper : tappers)
11378 if (tapper->IsAtGroupRewardDistance(victim))
11380 }
11381
11382 // Proc auras on death - must be before aura/combat remove
11384
11385 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
11386 // and before Spirit of Redemption as it also removes auras
11387 if (attacker)
11388 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
11389 killerPlayer->UpdateCriteria(CriteriaType::DeliveredKillingBlow, 1, 0, 0, victim);
11390
11391 if (!skipSettingDeathState)
11392 {
11393 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
11394 victim->setDeathState(JUST_DIED);
11395 }
11396
11397 // Inform pets (if any) when player kills target)
11398 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
11399 // selection will get stuck on same target and break pet react state
11400 for (Player* tapper : tappers)
11401 {
11402 Pet* pet = tapper->GetPet();
11403 if (pet && pet->IsAlive() && pet->isControlled())
11404 {
11405 if (pet->IsAIEnabled())
11406 pet->AI()->KilledUnit(victim);
11407 else
11408 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
11409 }
11410 }
11411
11412 // 10% durability loss on death
11413 if (Player* plrVictim = victim->ToPlayer())
11414 {
11415 // remember victim PvP death for corpse type and corpse reclaim delay
11416 // at original death (not at SpiritOfRedemtionTalent timeout)
11417 plrVictim->SetPvPDeath(player != nullptr);
11418
11419 // only if not player and not controlled by player pet. And not at BG
11420 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
11421 {
11422 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
11423 uint32 loss = uint32(baseLoss - (baseLoss * plrVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS)));
11424 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", loss);
11425 // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss
11426 plrVictim->DurabilityLossAll(baseLoss, false);
11427 // durability lost message
11428 plrVictim->SendDurabilityLoss(plrVictim, loss);
11429 }
11430 // Call KilledUnit for creatures
11431 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11432 attacker->ToCreature()->AI()->KilledUnit(victim);
11433
11434 // last damage from non duel opponent or opponent controlled creature
11435 if (plrVictim->duel)
11436 {
11437 plrVictim->duel->Opponent->CombatStopWithPets(true);
11438 plrVictim->CombatStopWithPets(true);
11439 plrVictim->DuelComplete(DUEL_INTERRUPTED);
11440 }
11441 }
11442 else // creature died
11443 {
11444 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
11445 ASSERT_NODEBUGINFO(creature);
11446
11447 if (!creature->IsPet())
11448 {
11449 // must be after setDeathState which resets dynamic flags
11450 if (!creature->IsFullyLooted())
11452 else
11453 creature->AllLootRemovedFromCorpse();
11454
11456 {
11459 }
11460 }
11461
11462 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
11463 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11464 attacker->ToCreature()->AI()->KilledUnit(victim);
11465
11466 // Call creature just died function
11467 if (CreatureAI* ai = creature->AI())
11468 {
11469 ai->OnHealthDepleted(attacker, true);
11470 ai->JustDied(attacker);
11471 }
11472
11473 if (TempSummon * summon = creature->ToTempSummon())
11474 {
11475 if (WorldObject * summoner = summon->GetSummoner())
11476 {
11477 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
11478 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
11479 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
11480 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
11481 }
11482 }
11483 }
11484
11485 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
11486 // handle player kill only if not suicide (spirit of redemption for example)
11487 if (player && attacker != victim)
11488 {
11489 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
11490 pvp->HandleKill(player, victim);
11491
11492 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
11493 bf->HandleKill(player, victim);
11494 }
11495
11496 //if (victim->GetTypeId() == TYPEID_PLAYER)
11497 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
11498 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
11499
11500 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
11501 if (attacker)
11502 {
11503 if (BattlegroundMap* bgMap = victim->GetMap()->ToBattlegroundMap())
11504 {
11505 if (Battleground* bg = bgMap->GetBG())
11506 {
11507 if (Player* playerVictim = victim->ToPlayer())
11508 {
11509 if (player)
11510 bg->HandleKillPlayer(playerVictim, player);
11511 }
11512 else
11513 bg->HandleKillUnit(victim->ToCreature(), attacker);
11514 }
11515 }
11516 }
11517
11518 // achievement stuff
11519 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
11520 {
11521 if (attacker->GetTypeId() == TYPEID_UNIT)
11523 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
11525 }
11526
11527 // Hook for OnPVPKill Event
11528 if (attacker)
11529 {
11530 if (Player* killerPlr = attacker->ToPlayer())
11531 {
11532 if (Player* killedPlr = victim->ToPlayer())
11533 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
11534 else if (Creature* killedCre = victim->ToCreature())
11535 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
11536 }
11537 else if (Creature* killerCre = attacker->ToCreature())
11538 {
11539 if (Player* killed = victim->ToPlayer())
11540 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
11541 }
11542 }
11543}
11544
11545void Unit::SetControlled(bool apply, UnitState state)
11546{
11547 if (apply)
11548 {
11549 if (HasUnitState(state))
11550 return;
11551
11552 if (state & UNIT_STATE_CONTROLLED)
11553 CastStop();
11554
11555 AddUnitState(state);
11556 switch (state)
11557 {
11558 case UNIT_STATE_STUNNED:
11559 SetStunned(true);
11560 break;
11561 case UNIT_STATE_ROOT:
11563 SetRooted(true);
11564 break;
11567 {
11569 // SendAutoRepeatCancel ?
11570 SetConfused(true);
11571 }
11572 break;
11573 case UNIT_STATE_FLEEING:
11575 {
11577 // SendAutoRepeatCancel ?
11578 SetFeared(true);
11579 }
11580 break;
11581 default:
11582 break;
11583 }
11584 }
11585 else
11586 {
11587 switch (state)
11588 {
11589 case UNIT_STATE_STUNNED:
11591 return;
11592
11593 ClearUnitState(state);
11594 SetStunned(false);
11595 break;
11596 case UNIT_STATE_ROOT:
11598 return;
11599
11600 ClearUnitState(state);
11602 SetRooted(false);
11603 break;
11606 return;
11607
11608 ClearUnitState(state);
11609 SetConfused(false);
11610 break;
11611 case UNIT_STATE_FLEEING:
11613 return;
11614
11615 ClearUnitState(state);
11616 SetFeared(false);
11617 break;
11618 default:
11619 return;
11620 }
11621
11623 }
11624}
11625
11627{
11628 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
11630 SetStunned(true);
11631
11633 SetRooted(true);
11634
11636 SetConfused(true);
11637
11639 SetFeared(true);
11640}
11641
11642void Unit::SetStunned(bool apply)
11643{
11644 if (apply)
11645 {
11648
11649 StopMoving();
11650
11651 if (GetTypeId() == TYPEID_PLAYER)
11653
11654 SetRooted(true);
11655
11656 CastStop();
11657 }
11658 else
11659 {
11660 if (IsAlive() && GetVictim())
11662
11663 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11664 Unit* owner = GetCharmerOrOwner();
11665 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11667
11668 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11669 SetRooted(false);
11670 }
11671}
11672
11673void Unit::SetRooted(bool apply)
11674{
11675 if (apply)
11676 {
11677 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11678 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11679 // setting MOVEMENTFLAG_ROOT
11682 StopMoving();
11683 }
11684 else
11686
11687 static OpcodeServer const rootOpcodeTable[2][2] =
11688 {
11691 };
11692
11693 if (Player* playerMover = GetPlayerMovingMe()) // unit controlled by a player.
11694 {
11695 WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]);
11696 packet.MoverGUID = GetGUID();
11698 playerMover->SendDirectMessage(packet.Write());
11699
11701 moveUpdate.Status = &m_movementInfo;
11702 SendMessageToSet(moveUpdate.Write(), playerMover);
11703 }
11704 else
11705 {
11706 WorldPackets::Movement::MoveSplineSetFlag packet(rootOpcodeTable[apply][0]);
11707 packet.MoverGUID = GetGUID();
11708 SendMessageToSet(packet.Write(), true);
11709 }
11710}
11711
11712void Unit::SetFeared(bool apply)
11713{
11714 if (apply)
11715 {
11717
11718 Unit* caster = nullptr;
11720 if (!fearAuras.empty())
11721 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11722 if (!caster)
11723 caster = getAttackerForHelper();
11724 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)) : 0ms); // caster == NULL processed in MoveFleeing
11726 }
11727 else
11728 {
11730 if (IsAlive())
11731 {
11733 if (Unit const* victim = GetVictim())
11734 SetTarget(victim->GetGUID());
11735 if (!IsPlayer() && !IsInCombat())
11737 }
11738 }
11739
11740 // block / allow control to real player in control (eg charmer)
11741 if (GetTypeId() == TYPEID_PLAYER)
11742 {
11743 if (m_playerMovingMe)
11744 m_playerMovingMe->SetClientControl(this, !apply);
11745 }
11746}
11747
11748void Unit::SetConfused(bool apply)
11749{
11750 if (apply)
11751 {
11754 }
11755 else
11756 {
11757 if (IsAlive())
11758 {
11760 if (GetVictim())
11762 }
11763 }
11764
11765 // block / allow control to real player in control (eg charmer)
11766 if (GetTypeId() == TYPEID_PLAYER)
11767 {
11768 if (m_playerMovingMe)
11769 m_playerMovingMe->SetClientControl(this, !apply);
11770 }
11771}
11772
11773bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11774{
11775 if (!charmer)
11776 return false;
11777
11778 // dismount players when charmed
11779 if (GetTypeId() == TYPEID_PLAYER)
11781
11782 if (charmer->GetTypeId() == TYPEID_PLAYER)
11784
11785 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11786 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11787
11788 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11789
11790 if (this == charmer)
11791 {
11792 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11793 return false;
11794 }
11795
11796 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11797 // return false;
11798
11800 {
11801 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11802 return false;
11803 }
11804
11805 // Already charmed
11806 if (!GetCharmerGUID().IsEmpty())
11807 {
11808 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11809 return false;
11810 }
11811
11812 CastStop();
11813 AttackStop();
11814
11815 Player* playerCharmer = charmer->ToPlayer();
11816
11817 // Charmer stop charming
11818 if (playerCharmer)
11819 {
11820 playerCharmer->StopCastingCharm();
11821 playerCharmer->StopCastingBindSight();
11822 }
11823
11824 // Charmed stop charming
11825 if (GetTypeId() == TYPEID_PLAYER)
11826 {
11829 }
11830
11831 // StopCastingCharm may remove a possessed pet?
11832 if (!IsInWorld())
11833 {
11834 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11835 return false;
11836 }
11837
11838 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11839 // prevent undefined behaviour
11840 if (aurApp && aurApp->GetRemoveMode())
11841 return false;
11842
11844 SetFaction(charmer->GetFaction());
11845
11846 // Pause any Idle movement
11847 PauseMovement(0, 0, false);
11848
11849 // Remove any active voluntary movement
11851
11852 // Stop any remaining spline, if no involuntary movement is found
11853 auto criteria = [](MovementGenerator const* movement) -> bool
11854 {
11855 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11856 };
11857 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11858 StopMoving();
11859
11860 // Set charmed
11861 charmer->SetCharm(this, true);
11862
11863 if (Player* player = ToPlayer())
11864 {
11865 if (player->isAFK())
11866 player->ToggleAFK();
11867
11868 player->SetClientControl(this, false);
11869 }
11870
11871 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11872 // prevent undefined behaviour
11873 if (aurApp && aurApp->GetRemoveMode())
11874 {
11875 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11878 charmer->SetCharm(this, false);
11879 return false;
11880 }
11881
11882 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11883 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11884 {
11885 InitCharmInfo();
11886 if (type == CHARM_TYPE_POSSESS)
11888 else
11890 }
11891
11892 if (playerCharmer)
11893 {
11894 switch (type)
11895 {
11896 case CHARM_TYPE_VEHICLE:
11898 playerCharmer->SetClientControl(this, true);
11899 playerCharmer->VehicleSpellInitialize();
11900 break;
11901 case CHARM_TYPE_POSSESS:
11904 playerCharmer->SetClientControl(this, true);
11905 playerCharmer->PossessSpellInitialize();
11907 break;
11908 case CHARM_TYPE_CHARM:
11909 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11910 {
11912 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11913 {
11914 // to prevent client crash
11916
11917 // just to enable stat window
11918 if (GetCharmInfo())
11919 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11920
11921 // if charmed two demons the same session, the 2nd gets the 1st one's name
11923 }
11924 }
11925 playerCharmer->CharmSpellInitialize();
11926 break;
11927 default:
11928 case CHARM_TYPE_CONVERT:
11929 break;
11930 }
11931 }
11932
11934
11935 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
11936 {
11937 // AI will schedule its own change if appropriate
11938 if (UnitAI* ai = GetAI())
11939 ai->OnCharmed(false);
11940 else
11942 }
11943 return true;
11944}
11945
11947{
11948 if (!IsCharmed())
11949 return;
11950
11951 if (charmer)
11952 ASSERT(charmer == GetCharmer());
11953 else
11954 charmer = GetCharmer();
11955
11956 ASSERT(charmer);
11957
11958 CharmType type;
11960 type = CHARM_TYPE_POSSESS;
11961 else if (charmer->IsOnVehicle(this))
11962 type = CHARM_TYPE_VEHICLE;
11963 else
11964 type = CHARM_TYPE_CHARM;
11965
11966 CastStop();
11967 AttackStop();
11968
11969 if (_oldFactionId)
11970 {
11972 _oldFactionId = 0;
11973 }
11974 else
11976
11979
11980 // Vehicle should not attack its passenger after he exists the seat
11981 if (type != CHARM_TYPE_VEHICLE)
11982 LastCharmerGUID = charmer->GetGUID();
11983
11984 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11986
11987 charmer->SetCharm(this, false);
11989
11990 Player* playerCharmer = charmer->ToPlayer();
11991 if (playerCharmer)
11992 {
11993 switch (type)
11994 {
11995 case CHARM_TYPE_VEHICLE:
11996 playerCharmer->SetClientControl(this, false);
11997 playerCharmer->SetClientControl(charmer, true);
11999 break;
12000 case CHARM_TYPE_POSSESS:
12002 playerCharmer->SetClientControl(this, false);
12003 playerCharmer->SetClientControl(charmer, true);
12006 break;
12007 case CHARM_TYPE_CHARM:
12008 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
12009 {
12011 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
12012 {
12013 SetClass(uint8(cinfo->unit_class));
12014 if (GetCharmInfo())
12015 GetCharmInfo()->SetPetNumber(0, true);
12016 else
12017 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
12018 }
12019 }
12020 break;
12021 case CHARM_TYPE_CONVERT:
12022 break;
12023 }
12024 }
12025
12026 if (Player* player = ToPlayer())
12027 player->SetClientControl(this, true);
12028
12029 if (playerCharmer && this != charmer->GetFirstControlled())
12030 playerCharmer->SendRemoveControlBar();
12031
12032 // a guardian should always have charminfo
12033 if (!IsGuardian())
12035
12036 // reset confused movement for example
12038
12039 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
12040 {
12041 if (UnitAI* charmedAI = GetAI())
12042 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
12043 else
12045 }
12046}
12047
12049{
12051 {
12052 SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).front()->GetMiscValue());
12053 return;
12054 }
12055
12056 if (GetTypeId() == TYPEID_PLAYER)
12058 else
12059 {
12061 {
12062 if (Unit* owner = GetOwner())
12063 {
12064 SetFaction(owner->GetFaction());
12065 return;
12066 }
12067 }
12068
12069 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
12070 SetFaction(cinfo->faction);
12071 }
12072}
12073
12074bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading /*= false*/)
12075{
12076 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
12077 if (!vehInfo)
12078 return false;
12079
12080 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
12081 m_updateFlag.Vehicle = true;
12083
12084 if (!loading)
12086
12087 return true;
12088}
12089
12090void Unit::RemoveVehicleKit(bool onRemoveFromWorld /*= false*/)
12091{
12092 if (!m_vehicleKit)
12093 return;
12094
12095 if (!onRemoveFromWorld)
12097
12099 m_vehicleKit = nullptr;
12100
12101 m_updateFlag.Vehicle = false;
12102 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
12104}
12105
12106bool Unit::IsOnVehicle(Unit const* vehicle) const
12107{
12108 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
12109}
12110
12112{
12113 return m_vehicle ? m_vehicle->GetBase() : nullptr;
12114}
12115
12117{
12118 Unit* vehicleRoot = GetVehicleBase();
12119
12120 if (!vehicleRoot)
12121 return nullptr;
12122
12123 for (;;)
12124 {
12125 if (!vehicleRoot->GetVehicleBase())
12126 return vehicleRoot;
12127
12128 vehicleRoot = vehicleRoot->GetVehicleBase();
12129 }
12130}
12131
12133{
12134 if (Unit* veh = GetVehicleBase())
12135 if (Creature* c = veh->ToCreature())
12136 return c;
12137
12138 return nullptr;
12139}
12140
12142{
12143 if (GetVehicle())
12144 return GetVehicleBase()->GetGUID();
12145 if (GetTransport())
12146 return GetTransport()->GetTransportGUID();
12147
12148 return ObjectGuid::Empty;
12149}
12150
12152{
12153 if (Vehicle* veh = GetVehicle())
12154 return veh;
12155 return GetTransport();
12156}
12157
12158bool Unit::IsInPartyWith(Unit const* unit) const
12159{
12160 if (this == unit)
12161 return true;
12162
12163 Unit const* u1 = GetCharmerOrOwnerOrSelf();
12164 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
12165 if (u1 == u2)
12166 return true;
12167
12168 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
12169 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
12170 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
12172 return true;
12173
12174 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
12175}
12176
12177bool Unit::IsInRaidWith(Unit const* unit) const
12178{
12179 if (this == unit)
12180 return true;
12181
12182 Unit const* u1 = GetCharmerOrOwnerOrSelf();
12183 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
12184 if (u1 == u2)
12185 return true;
12186
12187 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
12188 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
12189 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
12191 return true;
12192
12193 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
12194}
12195
12196void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
12197{
12198 Unit* owner = GetCharmerOrOwnerOrSelf();
12199 Group* group = nullptr;
12200 if (owner->GetTypeId() == TYPEID_PLAYER)
12201 group = owner->ToPlayer()->GetGroup();
12202
12203 if (group)
12204 {
12205 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
12206
12207 for (GroupReference const& itr : group->GetMembers())
12208 {
12209 Player* Target = itr.GetSource();
12210
12211 // IsHostileTo check duel and controlled by enemy
12212 if (Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
12213 {
12214 if (Target->IsAlive())
12215 TagUnitMap.push_back(Target);
12216
12217 if (Guardian* pet = Target->GetGuardianPet())
12218 if (pet->IsAlive())
12219 TagUnitMap.push_back(pet);
12220 }
12221 }
12222 }
12223 else
12224 {
12225 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
12226 TagUnitMap.push_back(owner);
12227 if (Guardian* pet = owner->GetGuardianPet())
12228 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
12229 TagUnitMap.push_back(pet);
12230 }
12231}
12232
12234{
12235 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
12236 return entry->IsContestedGuardFaction();
12237
12238 return false;
12239}
12240
12241void Unit::SetPvP(bool state)
12242{
12243 if (state)
12245 else
12247}
12248
12249Aura* Unit::AddAura(uint32 spellId, Unit* target)
12250{
12251 if (!target)
12252 return nullptr;
12253
12254 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
12255 if (!spellInfo)
12256 return nullptr;
12257
12258 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
12259}
12260
12261Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
12262{
12263 if (!spellInfo)
12264 return nullptr;
12265
12266 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
12267 return nullptr;
12268
12269 if (target->IsImmunedToSpell(spellInfo, effMask, this))
12270 return nullptr;
12271
12272 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
12273 {
12274 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
12275 continue;
12276
12277 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
12278 effMask &= ~(1 << spellEffectInfo.EffectIndex);
12279 }
12280
12281 if (!effMask)
12282 return nullptr;
12283
12284 ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>());
12285 AuraCreateInfo createInfo(castId, spellInfo, GetMap()->GetDifficultyID(), effMask, target);
12286 createInfo.SetCaster(this);
12287
12288 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
12289 {
12290 aura->ApplyForTargets();
12291 return aura;
12292 }
12293 return nullptr;
12294}
12295
12296void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
12297{
12298 Aura* aura = target->GetAura(spellId, GetGUID());
12299 if (!aura)
12300 aura = AddAura(spellId, target);
12301 if (aura && stack)
12302 aura->SetStackAmount(stack);
12303}
12304
12305void Unit::SendPlaySpellVisual(Unit* target, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12306{
12308 playSpellVisual.Source = GetGUID();
12309 playSpellVisual.Target = target->GetGUID();
12310 playSpellVisual.TargetPosition = target->GetPosition();
12311 playSpellVisual.SpellVisualID = spellVisualId;
12312 playSpellVisual.TravelSpeed = travelSpeed;
12313 playSpellVisual.MissReason = missReason;
12314 playSpellVisual.ReflectStatus = reflectStatus;
12315 playSpellVisual.SpeedAsTime = speedAsTime;
12316 playSpellVisual.LaunchDelay = launchDelay;
12317 SendMessageToSet(playSpellVisual.Write(), true);
12318}
12319
12320void Unit::SendPlaySpellVisual(Position const& targetPosition, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12321{
12323 playSpellVisual.Source = GetGUID();
12324 playSpellVisual.TargetPosition = targetPosition;
12325 playSpellVisual.SpellVisualID = spellVisualId;
12326 playSpellVisual.TravelSpeed = travelSpeed;
12327 playSpellVisual.MissReason = missReason;
12328 playSpellVisual.ReflectStatus = reflectStatus;
12329 playSpellVisual.SpeedAsTime = speedAsTime;
12330 playSpellVisual.LaunchDelay = launchDelay;
12331 SendMessageToSet(playSpellVisual.Write(), true);
12332}
12333
12335{
12337 cancelSpellVisual.Source = GetGUID();
12338 cancelSpellVisual.SpellVisualID = id;
12339 SendMessageToSet(cancelSpellVisual.Write(), true);
12340}
12341
12342void Unit::SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
12343{
12345 playSpellVisualKit.Unit = GetGUID();
12346 playSpellVisualKit.KitRecID = id;
12347 playSpellVisualKit.KitType = type;
12348 playSpellVisualKit.Duration = duration;
12349 SendMessageToSet(playSpellVisualKit.Write(), true);
12350}
12351
12353{
12354 WorldPackets::Spells::CancelSpellVisualKit cancelSpellVisualKit;
12355 cancelSpellVisualKit.Source = GetGUID();
12356 cancelSpellVisualKit.SpellVisualKitID = id;
12357 SendMessageToSet(cancelSpellVisualKit.Write(), true);
12358}
12359
12360void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/, bool abortSpell /*= false*/)
12361{
12362 bool hasMissile = false;
12363 if (abortSpell)
12364 {
12365 for (std::pair<uint64 const, BasicEvent*> const& itr : m_Events.GetEvents())
12366 {
12367 if (Spell const* spell = Spell::ExtractSpellFromEvent(itr.second))
12368 {
12369 if (spell->GetSpellInfo()->Id == spellId)
12370 {
12371 itr.second->ScheduleAbort();
12372 hasMissile = true;
12373 }
12374 }
12375 }
12376 }
12377 else
12378 hasMissile = true;
12379
12380 if (hasMissile)
12381 {
12383 packet.OwnerGUID = GetGUID();
12384 packet.SpellID = spellId;
12385 packet.Reverse = reverseMissile;
12386 SendMessageToSet(packet.Write(), false);
12387 }
12388}
12389
12391{
12392 return !IsVehicle() && GetOwnerGUID().IsPlayer();
12393}
12394
12395/*static*/ void Unit::ApplyResilience(Unit const* victim, int32* damage)
12396{
12397 // player mounted on multi-passenger mount is also classified as vehicle
12398 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
12399 return;
12400
12401 Unit const* target = nullptr;
12402 if (victim->GetTypeId() == TYPEID_PLAYER)
12403 target = victim;
12404 else // victim->GetTypeId() == TYPEID_UNIT
12405 {
12406 if (Unit* owner = victim->GetOwner())
12407 if (owner->GetTypeId() == TYPEID_PLAYER)
12408 target = owner;
12409 }
12410
12411 if (!target)
12412 return;
12413
12414 *damage -= target->GetDamageReduction(*damage);
12415}
12416
12417int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
12418{
12419 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
12420 if (npcCaster)
12422
12423 return damage;
12424}
12425
12426// Melee based spells can be miss, parry or dodge on this step
12427// Crit or block - determined on damage calculation phase! (and can be both in some time)
12428float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const
12429{
12430 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
12431 return 0.f;
12432
12433 //calculate miss chance
12434 float missChance = victim->GetUnitMissChance();
12435
12436 // melee attacks while dual wielding have +19% chance to miss
12438 missChance += 19.0f;
12439
12440 // Spellmod from SpellModOp::HitChance
12441 float resistMissChance = 100.0f;
12442 if (spellInfo)
12443 if (Player* modOwner = GetSpellModOwner())
12444 modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, resistMissChance);
12445
12446 missChance -= resistMissChance - 100.0f;
12447
12448 if (attType == RANGED_ATTACK)
12449 missChance -= m_modRangedHitChance;
12450 else
12451 missChance -= m_modMeleeHitChance;
12452
12453 // miss chance from auras after calculating skill based miss
12455 if (attType == RANGED_ATTACK)
12457 else
12459
12460 return std::max(missChance, 0.f);
12461}
12462
12464{
12465}
12466
12468{
12469 if (!forced)
12471 else
12472 {
12474 // call MoveInLineOfSight for nearby creatures
12475 Trinity::AIRelocationNotifier notifier(*this);
12476 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
12477 }
12478}
12479
12480void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
12481{
12483 moveKnockBack.MoverGUID = GetGUID();
12484 moveKnockBack.SequenceIndex = m_movementCounter++;
12485 moveKnockBack.Speeds.HorzSpeed = speedXY;
12486 moveKnockBack.Speeds.VertSpeed = speedZ;
12487 moveKnockBack.Direction = Position(vcos, vsin);
12488 player->GetSession()->SendPacket(moveKnockBack.Write());
12489}
12490
12491void Unit::KnockbackFrom(Position const& origin, float speedXY, float speedZ, float angle /*= M_PI*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
12492{
12493 Player* player = ToPlayer();
12494 if (!player)
12495 {
12496 if (Unit* charmer = GetCharmer())
12497 {
12498 player = charmer->ToPlayer();
12499 if (player && player->GetUnitBeingMoved() != this)
12500 player = nullptr;
12501 }
12502 }
12503
12504 if (!player)
12505 GetMotionMaster()->MoveKnockbackFrom(origin, speedXY, speedZ, angle, spellEffectExtraData);
12506 else
12507 {
12508 float o = (GetPosition() == origin ? GetOrientation() : GetAbsoluteAngle(origin)) + angle;
12509 if (speedXY < 0)
12510 {
12511 speedXY = -speedXY;
12512 o = o - float(M_PI);
12513 }
12514
12515 float vcos = std::cos(o);
12516 float vsin = std::sin(o);
12517 SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
12518 }
12519}
12520
12522{
12523 if (Player const* player = ToPlayer())
12524 return player->GetRatingBonusValue(cr);
12525 // Player's pet get resilience from owner
12526 else if (IsPet() && GetOwner())
12527 if (Player* owner = GetOwner()->ToPlayer())
12528 return owner->GetRatingBonusValue(cr);
12529
12530 return 0.0f;
12531}
12532
12533uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
12534{
12535 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
12536 return CalculatePct(damage, percent);
12537}
12538
12540{
12541 // Hardcoded cases
12542 switch (spellId)
12543 {
12544 case 7090: // Bear Form
12545 return 29414;
12546 case 35200: // Roc Form
12547 return 4877;
12548 case 24858: // Moonkin Form
12549 {
12550 if (HasAura(114301)) // Glyph of Stars
12551 return 0;
12552 break;
12553 }
12554 default:
12555 break;
12556 }
12557
12558 if (Player const* player = ToPlayer())
12559 {
12561 if (Item* artifact = player->GetItemByGuid(artifactAura->GetCastItemGUID()))
12562 if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)))
12563 if (ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID) == form)
12564 return artifactAppearance->OverrideShapeshiftDisplayID;
12565
12566 if (ShapeshiftFormModelData const* formModelData = sDB2Manager.GetShapeshiftFormModelData(GetRace(), player->GetNativeGender(), form))
12567 {
12568 bool useRandom = false;
12569 switch (form)
12570 {
12571 case FORM_CAT_FORM: useRandom = HasAura(210333); break; // Glyph of the Feral Chameleon
12572 case FORM_TRAVEL_FORM: useRandom = HasAura(344336); break; // Glyph of the Swift Chameleon
12573 case FORM_AQUATIC_FORM: useRandom = HasAura(344338); break; // Glyph of the Aquatic Chameleon
12575 case FORM_BEAR_FORM: useRandom = HasAura(107059); break; // Glyph of the Ursol Chameleon
12577 case FORM_FLIGHT_FORM: useRandom = HasAura(344342); break; // Glyph of the Aerial Chameleon
12578 default:
12579 break;
12580 }
12581
12582 if (useRandom)
12583 {
12584 std::vector<uint32> displayIds;
12585 displayIds.reserve(formModelData->Choices->size());
12586
12587 for (std::size_t i = 0; i < formModelData->Choices->size(); ++i)
12588 {
12589 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[i])
12590 {
12591 ChrCustomizationReqEntry const* choiceReq = sChrCustomizationReqStore.LookupEntry((*formModelData->Choices)[i]->ChrCustomizationReqID);
12592 if (!choiceReq || player->GetSession()->MeetsChrCustomizationReq(choiceReq, Races(GetRace()), Classes(GetClass()), false,
12593 MakeChrCustomizationChoiceRange(player->m_playerData->Customizations)))
12594 displayIds.push_back(displayInfo->DisplayID);
12595 }
12596 }
12597
12598 if (!displayIds.empty())
12600 }
12601 else
12602 {
12603 if (uint32 formChoice = player->GetCustomizationChoice(formModelData->OptionID))
12604 {
12605 auto choiceItr = std::find_if(formModelData->Choices->begin(), formModelData->Choices->end(), [formChoice](ChrCustomizationChoiceEntry const* choice)
12606 {
12607 return choice->ID == formChoice;
12608 });
12609
12610 if (choiceItr != formModelData->Choices->end())
12611 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[std::distance(formModelData->Choices->begin(), choiceItr)])
12612 return displayInfo->DisplayID;
12613 }
12614 }
12615 }
12616 switch (form)
12617 {
12618 case FORM_GHOST_WOLF:
12619 {
12620 if (HasAura(58135)) // Glyph of Spectral Wolf
12621 return 60247;
12622 break;
12623 }
12624 default:
12625 break;
12626 }
12627 }
12628
12629 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
12630 if (formEntry && formEntry->CreatureDisplayID)
12631 return formEntry->CreatureDisplayID;
12632
12633 return 0;
12634}
12635
12636void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12637{
12638 bool spellClickHandled = false;
12639 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12641
12642 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12643 for (auto const& clickPair : clickBounds)
12644 {
12646 if (!clickPair.second.IsFitToRequirements(clicker, this))
12647 continue;
12648
12650 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12651 continue;
12652
12653 spellClickHandled = HandleSpellClick(clicker, seatId, clickPair.second.spellId, flags, &clickPair.second);
12654
12655 // if (!spellEntry) should be checked at npc_spellclick load
12656 }
12657
12658 Creature* creature = ToCreature();
12659 if (creature && creature->IsAIEnabled())
12660 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12661}
12662
12663bool Unit::HandleSpellClick(Unit* clicker, int8 seatId, uint32 spellId, TriggerCastFlags flags /*= TRIGGERED_NONE*/, SpellClickInfo const* spellClickInfo /*= nullptr*/)
12664{
12665 Unit* caster = clicker;
12666 Unit* target = this;
12667 ObjectGuid origCasterGUID = caster->GetGUID();
12669
12670 if (spellClickInfo)
12671 {
12672 caster = (spellClickInfo->castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12673 target = (spellClickInfo->castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12674 origCasterGUID = (spellClickInfo->castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12675 }
12676
12677 if (!spellId)
12678 {
12679 TC_LOG_ERROR("sql.sql", "No valid spell specified for clickee {} and clicker {}!", target->GetGUID(), caster->GetGUID());
12680 return false;
12681 }
12682
12683 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(spellId, caster->GetMap()->GetDifficultyID());
12684
12685 uint8 effectIndex = 0;
12686 bool hasControlVehicleAura = false;
12687 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12688 {
12689 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12690 {
12691 hasControlVehicleAura = true;
12692 break;
12693 }
12694 ++effectIndex;
12695 }
12696
12697 if (seatId > -1)
12698 {
12699 if (!hasControlVehicleAura)
12700 {
12701 if (!spellClickInfo)
12702 TC_LOG_ERROR("sql.sql", "RideSpell {} specified in vehicle_accessory or vehicle_template_accessory is not a valid vehicle enter aura!", spellId);
12703 else
12704 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", spellId);
12705 return false;
12706 }
12707
12708 if (IsInMap(caster))
12709 {
12711 args.OriginalCaster = origCasterGUID;
12712 args.AddSpellMod(SpellValueModFloat(SPELLVALUE_BASE_POINT0 + effectIndex), seatId + 1);
12713 castResult = caster->CastSpell(target, spellId, args);
12714 }
12715 else // This can happen during Player::_LoadAuras
12716 {
12717 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> bp = { };
12718 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12719 bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
12720
12721 bp[effectIndex] = seatId;
12722
12723 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12724 createInfo
12725 .SetCaster(clicker)
12726 .SetBaseAmount(bp.data())
12727 .SetCasterGUID(origCasterGUID);
12728
12730 }
12731 }
12732 else
12733 {
12734 if (IsInMap(caster))
12735 castResult = caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12736 else
12737 {
12738 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12739 createInfo
12740 .SetCaster(clicker)
12741 .SetCasterGUID(origCasterGUID);
12742
12744 }
12745 }
12746 return castResult == SPELL_FAILED_SUCCESS;
12747}
12748
12749void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12750{
12752 args.AddSpellMod(SPELLVALUE_BASE_POINT0, seatId + 1);
12754}
12755
12756void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12757{
12758 // Must be called only from aura handler
12759 ASSERT(aurApp);
12760
12761 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12762 return;
12763
12764 if (m_vehicle)
12765 {
12766 if (m_vehicle != vehicle)
12767 {
12768 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12769 ExitVehicle();
12770 }
12771 else if (seatId >= 0 && seatId == GetTransSeat())
12772 return;
12773 else
12774 {
12775 //Exit the current vehicle because unit will reenter in a new seat.
12777 }
12778 }
12779
12780 if (aurApp->GetRemoveMode())
12781 return;
12782
12783 if (Player* player = ToPlayer())
12784 {
12785 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12786 {
12787 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12788 return;
12789 }
12790
12791 if (Creature* vehicleBaseCreature = vehicle->GetBase()->ToCreature())
12792 {
12793 // If a player entered a vehicle that is part of a formation, remove it from said formation
12794 if (CreatureGroup* creatureGroup = vehicleBaseCreature->GetFormation())
12795 FormationMgr::RemoveCreatureFromGroup(creatureGroup, vehicleBaseCreature);
12796 }
12797 }
12798
12799 ASSERT(!m_vehicle);
12800 (void)vehicle->AddVehiclePassenger(this, seatId);
12801}
12802
12803void Unit::ChangeSeat(int8 seatId, bool next)
12804{
12805 if (!m_vehicle)
12806 return;
12807
12808 // Don't change if current and new seat are identical
12809 if (seatId == GetTransSeat())
12810 return;
12811
12812 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12813 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12814 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12815 return;
12816
12817 AuraEffect* rideVehicleEffect = nullptr;
12819 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12820 {
12821 if ((*itr)->GetCasterGUID() != GetGUID())
12822 continue;
12823
12824 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12825 ASSERT(!rideVehicleEffect);
12826 rideVehicleEffect = *itr;
12827 }
12828
12829 // Unit riding a vehicle must always have control vehicle aura on target
12830 ASSERT(rideVehicleEffect);
12831
12832 rideVehicleEffect->ChangeAmount(seat->first + 1);
12833}
12834
12835void Unit::ExitVehicle(Position const* /*exitPosition*/)
12836{
12838 if (!m_vehicle)
12839 return;
12840
12845 /*_ExitVehicle(exitPosition);*/
12852}
12853
12854void Unit::_ExitVehicle(Position const* exitPosition)
12855{
12859 if (!m_vehicle)
12860 return;
12861
12862 // This should be done before dismiss, because there may be some aura removal
12864 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12865
12866 if (!vehicle)
12867 {
12868 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12869 return;
12870 }
12871
12872 Player* player = ToPlayer();
12873
12874 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12875 if (player && player->duel && player->duel->IsMounted)
12876 player->DuelComplete(DUEL_FLED);
12877
12878 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12879
12881
12882 if (player)
12883 player->SetFallInformation(0, GetPositionZ());
12884
12885 Position pos;
12886 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12887 if (exitPosition)
12888 pos = *exitPosition;
12889 else
12890 {
12891 // Set exit position to vehicle position and use the current orientation
12892 pos = vehicle->GetBase()->GetPosition();
12894
12895 // Change exit position based on seat entry addon data
12896 if (seatAddon)
12897 {
12899 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12901 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12902 }
12903 }
12904
12905 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
12906 {
12907 float height = pos.GetPositionZ() + vehicleCollisionHeight;
12908
12909 // Creatures without inhabit type air should begin falling after exiting the vehicle
12910 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
12911 init.SetFall();
12912
12913 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
12914 init.SetFacing(pos.GetOrientation());
12915 init.SetTransportExit();
12916 };
12918
12919 if (player)
12921
12922 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12923 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
12924 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
12925
12927 {
12928 // Vehicle just died, we die too
12929 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
12931 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
12932 else
12933 ToTempSummon()->UnSummon(2000); // Approximation
12934 }
12935
12937}
12938
12943
12944bool Unit::CanSwim() const
12945{
12946 // 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
12948 return false;
12949 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
12950 return true;
12952 return false;
12954 return true;
12956}
12957
12958void Unit::NearTeleportTo(TeleportLocation const& target, bool casting)
12959{
12960 DisableSpline();
12961 if (GetTypeId() == TYPEID_PLAYER)
12963 else
12964 {
12965 SendTeleportPacket(target);
12966 UpdatePosition(target.Location, true);
12968 }
12969}
12970
12971void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
12972{
12973 NearTeleportTo(TeleportLocation{ .Location = { GetMapId(), pos } }, casting);
12974}
12975
12976void Unit::SendTeleportPacket(TeleportLocation const& teleportLocation)
12977{
12978 // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
12979 // SMSG_MOVE_TELEPORT is sent to self in order to trigger CMSG_MOVE_TELEPORT_ACK and update the position server side
12980
12982 moveUpdateTeleport.Status = &m_movementInfo;
12983 if (_movementForces)
12984 moveUpdateTeleport.MovementForces = _movementForces->GetForces();
12985 Unit* broadcastSource = this;
12986
12987 // should this really be the unit _being_ moved? not the unit doing the moving?
12988 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12989 {
12991 moveTeleport.MoverGUID = GetGUID();
12992 moveTeleport.Pos = teleportLocation.Location;
12993 moveTeleport.TransportGUID = teleportLocation.TransportGuid;
12994 moveTeleport.Facing = teleportLocation.Location.GetOrientation();
12995 moveTeleport.SequenceIndex = m_movementCounter++;
12996 playerMover->SendDirectMessage(moveTeleport.Write());
12997
12998 broadcastSource = playerMover;
12999 }
13000 else
13001 {
13002 // This is the only packet sent for creatures which contains MovementInfo structure
13003 // we do not update m_movementInfo for creatures so it needs to be done manually here
13004 moveUpdateTeleport.Status->guid = GetGUID();
13005 moveUpdateTeleport.Status->time = getMSTime();
13006
13007 if (teleportLocation.TransportGuid)
13008 {
13009 Transport* transport = GetMap()->GetTransport(*teleportLocation.TransportGuid);
13010 if (!transport)
13011 return;
13012
13013 moveUpdateTeleport.Status->pos.Relocate(transport->GetPositionWithOffset(teleportLocation.Location));
13014 moveUpdateTeleport.Status->transport.pos.Relocate(teleportLocation.Location);
13015 }
13016 else
13017 {
13018 moveUpdateTeleport.Status->pos.Relocate(teleportLocation.Location);
13019 moveUpdateTeleport.Status->transport.Reset();
13020 }
13021 }
13022
13023 // Broadcast the packet to everyone except self.
13024 broadcastSource->SendMessageToSet(moveUpdateTeleport.Write(), false);
13025}
13026
13027bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
13028{
13029 // prevent crash when a bad coord is sent by the client
13030 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
13031 {
13032 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
13033 return false;
13034 }
13035
13036 // Check if angular distance changed
13037 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
13038
13039 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
13040 bool const relocated = (teleport ||
13041 std::fabs(GetPositionX() - x) > 0.001f ||
13042 std::fabs(GetPositionY() - y) > 0.001f ||
13043 std::fabs(GetPositionZ() - z) > 0.001f);
13044
13045 if (relocated)
13046 {
13047 // move and update visible state if need
13048 if (GetTypeId() == TYPEID_PLAYER)
13049 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
13050 else
13051 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
13052
13054 for (AuraEffect const* auraEffect : controlZoneAuras)
13055 if (GameObject* controlZone = GetGameObject(auraEffect->GetSpellInfo()->Id))
13056 GetMap()->GameObjectRelocation(controlZone, x, y, z, orientation);
13057 }
13058 else if (turn)
13059 UpdateOrientation(orientation);
13060
13061 _positionUpdateInfo.Relocated = relocated;
13063
13064 if (IsFalling())
13066
13067 bool isInWater = IsInWater();
13068 if (!IsFalling() || isInWater || IsFlying())
13070
13071 if (isInWater)
13073
13074 return (relocated || turn);
13075}
13076
13077bool Unit::UpdatePosition(Position const& pos, bool teleport)
13078{
13079 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
13080}
13081
13083void Unit::UpdateOrientation(float orientation)
13084{
13085 SetOrientation(orientation);
13086 if (IsVehicle())
13088}
13089
13091void Unit::UpdateHeight(float newZ)
13092{
13094 if (IsVehicle())
13096}
13097
13098// baseRage means damage taken when attacker = false
13100{
13101 float addRage = baseRage;
13102
13103 // talent who gave more rage on attack
13105
13106 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
13107
13108 return ModifyPower(POWER_RAGE, uint32(addRage * 10), false);
13109}
13110
13112{
13113 if (Unit* victim = GetVictim())
13114 {
13115 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
13116 {
13117 AttackStop();
13118 if (IsNonMeleeSpellCast(false))
13120
13121 // melee and ranged forced attack cancel
13122 if (GetTypeId() == TYPEID_PLAYER)
13124 }
13125 }
13126
13127 AttackerSet const& attackers = getAttackers();
13128 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
13129 {
13130 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
13131 {
13132 (*itr)->AttackStop();
13133 itr = attackers.begin();
13134 }
13135 else
13136 ++itr;
13137 }
13138
13139 std::vector<CombatReference*> refsToEnd;
13140 for (auto const& pair : m_combatManager.GetPvECombatRefs())
13141 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
13142 refsToEnd.push_back(pair.second);
13143 for (CombatReference* ref : refsToEnd)
13144 ref->EndCombat();
13145
13146 for (Unit* minion : m_Controlled)
13147 minion->StopAttackFaction(faction_id);
13148}
13149
13151{
13152 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
13153 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
13154 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
13155 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
13156 if (IsInWorld())
13157 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
13158
13159 std::ostringstream o;
13160 o << "Summon Slot: ";
13161 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
13162 o << m_SummonSlot[i].ToString() << ", ";
13163
13164 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13165 o.str("");
13166
13167 o << "Controlled List: ";
13168 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
13169 o << (*itr)->GetGUID().ToString() << ", ";
13170 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13171 o.str("");
13172
13173 o << "Aura List: ";
13174 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
13175 o << itr->first << ", ";
13176 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13177 o.str("");
13178
13179 if (IsVehicle())
13180 {
13181 o << "Passenger List: ";
13182 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
13183 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
13184 o << passenger->GetGUID().ToString() << ", ";
13185 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13186 }
13187
13188 if (GetVehicle())
13189 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
13190}
13191
13193{
13195 breakTarget.UnitGUID = GetGUID();
13196 SendMessageToSet(breakTarget.Write(), false);
13197}
13198
13200{
13201 Optional<int32> resist;
13202 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
13203 {
13204 int32 schoolResistance = GetResistance(SpellSchools(i));
13205 if (mask & (1 << i) && (!resist || *resist > schoolResistance))
13206 resist = schoolResistance;
13207 }
13208
13209 return resist.value_or(0);
13210}
13211
13213{
13214 _isCommandAttack = val;
13215}
13216
13218{
13219 return _isCommandAttack;
13220}
13221
13223{
13224 _isCommandFollow = val;
13225}
13226
13228{
13229 return _isCommandFollow;
13230}
13231
13233{
13235 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
13236
13237 if (_unit->movespline->onTransport)
13238 if (TransportBase* transport = _unit->GetDirectTransport())
13239 transport->GetPositionWithOffset({ stayPos.x, stayPos.y, stayPos.z }).GetPosition(stayPos.x, stayPos.y, stayPos.z);
13240
13241 _stayX = stayPos.x;
13242 _stayY = stayPos.y;
13243 _stayZ = stayPos.z;
13244}
13245
13246void CharmInfo::GetStayPosition(float &x, float &y, float &z)
13247{
13248 x = _stayX;
13249 y = _stayY;
13250 z = _stayZ;
13251}
13252
13254{
13255 _isAtStay = val;
13256}
13257
13259{
13260 return _isAtStay;
13261}
13262
13264{
13265 _isFollowing = val;
13266}
13267
13269{
13270 return _isFollowing;
13271}
13272
13274{
13275 _isReturning = val;
13276}
13277
13279{
13280 return _isReturning;
13281}
13282
13284{
13287}
13288
13289void Unit::SetFacingTo(float ori, bool force)
13290{
13291 // do not face when already moving
13292 if (!force && (!IsStopped() || !movespline->Finalized()))
13293 return;
13294
13295 Movement::MoveSplineInit init(this);
13296 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13297 if (GetTransport())
13298 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
13299 init.SetFacing(ori);
13300
13301 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13303 if (Creature* creature = ToCreature())
13304 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13305}
13306
13307void Unit::SetFacingToObject(WorldObject const* object, bool force)
13308{
13309 // do not face when already moving
13310 if (!force && (!IsStopped() || !movespline->Finalized()))
13311 return;
13312
13314 Movement::MoveSplineInit init(this);
13315 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13316 init.SetFacing(GetAbsoluteAngle(object)); // when on transport, GetAbsoluteAngle will still return global coordinates (and angle) that needs transforming
13317
13318 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13320 if (Creature* creature = ToCreature())
13321 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13322}
13323
13324void Unit::SetFacingToPoint(Position const& point, bool force)
13325{
13326 // do not face when already moving
13327 if (!force && (!IsStopped() || !movespline->Finalized()))
13328 return;
13329
13331 Movement::MoveSplineInit init(this);
13332 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13333 if (GetTransport())
13334 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
13335 init.SetFacing(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
13336
13337 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13339 if (Creature* creature = ToCreature())
13340 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13341}
13342
13343bool Unit::SetWalk(bool enable)
13344{
13345 if (enable == IsWalking())
13346 return false;
13347
13348 if (enable)
13350 else
13352
13354
13355 WorldPackets::Movement::MoveSplineSetFlag packet(walkModeTable[enable]);
13356 packet.MoverGUID = GetGUID();
13357 SendMessageToSet(packet.Write(), true);
13358 return true;
13359}
13360
13361bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/)
13362{
13363 if (disable == IsGravityDisabled())
13364 return false;
13365
13366 if (disable)
13367 {
13370 }
13371 else
13373
13374 static OpcodeServer const gravityOpcodeTable[2][2] =
13375 {
13378 };
13379
13380 if (Player* playerMover = GetPlayerMovingMe())
13381 {
13382 WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]);
13383 packet.MoverGUID = GetGUID();
13385 playerMover->SendDirectMessage(packet.Write());
13386
13388 moveUpdate.Status = &m_movementInfo;
13389 SendMessageToSet(moveUpdate.Write(), playerMover);
13390 }
13391 else
13392 {
13393 WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]);
13394 packet.MoverGUID = GetGUID();
13395 SendMessageToSet(packet.Write(), true);
13396 }
13397
13398 if (!GetVehicle())
13399 {
13400 if (IsAlive())
13401 {
13402 if (IsGravityDisabled() || IsHovering())
13403 SetPlayHoverAnim(true);
13404 else
13405 SetPlayHoverAnim(false);
13406 }
13407 else if (IsPlayer()) // To update player who dies while flying/hovering
13408 SetPlayHoverAnim(false, false);
13409 }
13410
13411 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT))
13412 {
13413 if (IsGravityDisabled())
13415 else if (IsHovering())
13417 else
13419 }
13420
13421 return true;
13422}
13423
13424bool Unit::SetFall(bool enable)
13425{
13427 return false;
13428
13429 if (enable)
13430 {
13433 }
13434 else
13436
13437 return true;
13438}
13439
13440bool Unit::SetSwim(bool enable)
13441{
13443 return false;
13444
13445 if (enable)
13447 else
13449
13450 static OpcodeServer const swimOpcodeTable[2] = { SMSG_MOVE_SPLINE_STOP_SWIM, SMSG_MOVE_SPLINE_START_SWIM};
13451
13452 WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]);
13453 packet.MoverGUID = GetGUID();
13454 SendMessageToSet(packet.Write(), true);
13455
13456 return true;
13457}
13458
13459bool Unit::SetCanFly(bool enable)
13460{
13462 return false;
13463
13464 if (enable)
13465 {
13468 }
13469 else
13471
13472 static OpcodeServer const flyOpcodeTable[2][2] =
13473 {
13476 };
13477
13478 if (!enable && GetTypeId() == TYPEID_PLAYER)
13480
13481 if (Player* playerMover = GetPlayerMovingMe())
13482 {
13483 WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]);
13484 packet.MoverGUID = GetGUID();
13486 playerMover->SendDirectMessage(packet.Write());
13487
13489 moveUpdate.Status = &m_movementInfo;
13490 SendMessageToSet(moveUpdate.Write(), playerMover);
13491 }
13492 else
13493 {
13494 WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]);
13495 packet.MoverGUID = GetGUID();
13496 SendMessageToSet(packet.Write(), true);
13497 }
13498
13499 return true;
13500}
13501
13502bool Unit::SetWaterWalking(bool enable)
13503{
13505 return false;
13506
13507 if (enable)
13509 else
13511
13512 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
13513 {
13516 };
13517
13518 if (Player* playerMover = GetPlayerMovingMe())
13519 {
13520 WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]);
13521 packet.MoverGUID = GetGUID();
13523 playerMover->SendDirectMessage(packet.Write());
13524
13526 moveUpdate.Status = &m_movementInfo;
13527 SendMessageToSet(moveUpdate.Write(), playerMover);
13528 }
13529 else
13530 {
13531 WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]);
13532 packet.MoverGUID = GetGUID();
13533 SendMessageToSet(packet.Write(), true);
13534 }
13535
13536 return true;
13537}
13538
13539bool Unit::SetFeatherFall(bool enable)
13540{
13541 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13542 //if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW))
13543 // return false;
13544
13545 if (enable)
13547 else
13549
13550 static OpcodeServer const featherFallOpcodeTable[2][2] =
13551 {
13554 };
13555
13556 if (Player* playerMover = GetPlayerMovingMe())
13557 {
13558 WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]);
13559 packet.MoverGUID = GetGUID();
13561 playerMover->SendDirectMessage(packet.Write());
13562
13564 moveUpdate.Status = &m_movementInfo;
13565 SendMessageToSet(moveUpdate.Write(), playerMover);
13566 }
13567 else
13568 {
13569 WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]);
13570 packet.MoverGUID = GetGUID();
13571 SendMessageToSet(packet.Write(), true);
13572 }
13573
13574 return true;
13575}
13576
13577bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
13578{
13580 return false;
13581
13582 float hoverHeight = m_unitData->HoverHeight;
13583
13584 if (enable)
13585 {
13588 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
13589 UpdateHeight(GetPositionZ() + hoverHeight);
13590 }
13591 else
13592 {
13595 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
13596 {
13597 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
13599 UpdateHeight(newZ);
13600 }
13601 }
13602
13603 static OpcodeServer const hoverOpcodeTable[2][2] =
13604 {
13607 };
13608
13609 if (Player* playerMover = GetPlayerMovingMe())
13610 {
13611 WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]);
13612 packet.MoverGUID = GetGUID();
13614 playerMover->SendDirectMessage(packet.Write());
13615
13617 moveUpdate.Status = &m_movementInfo;
13618 SendMessageToSet(moveUpdate.Write(), playerMover);
13619 }
13620 else
13621 {
13622 WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]);
13623 packet.MoverGUID = GetGUID();
13624 SendMessageToSet(packet.Write(), true);
13625 }
13626
13627 if (IsAlive())
13628 {
13629 if (IsGravityDisabled() || IsHovering())
13630 SetPlayHoverAnim(true);
13631 else
13632 SetPlayHoverAnim(false);
13633 }
13634 else if (IsPlayer()) // To update player who dies while flying/hovering
13635 SetPlayHoverAnim(false, false);
13636
13637 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT))
13638 {
13639 if (IsGravityDisabled())
13641 else if (IsHovering())
13643 else
13645 }
13646
13647 return true;
13648}
13649
13650bool Unit::SetCollision(bool disable)
13651{
13653 return false;
13654
13655 if (disable)
13657 else
13659
13660 static OpcodeServer const collisionOpcodeTable[2][2] =
13661 {
13664 };
13665
13666 if (Player* playerMover = GetPlayerMovingMe())
13667 {
13668 WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]);
13669 packet.MoverGUID = GetGUID();
13671 playerMover->SendDirectMessage(packet.Write());
13672
13674 moveUpdate.Status = &m_movementInfo;
13675 SendMessageToSet(moveUpdate.Write(), playerMover);
13676 }
13677 else
13678 {
13679 WorldPackets::Movement::MoveSplineSetFlag packet(collisionOpcodeTable[disable][0]);
13680 packet.MoverGUID = GetGUID();
13681 SendMessageToSet(packet.Write(), true);
13682 }
13683
13684 return true;
13685}
13686
13688{
13690 return false;
13691
13692 if (disable)
13694 else
13696
13697 static OpcodeServer const disableStrafingOpcodeTable[2] =
13698 {
13701 };
13702
13703 if (Player* playerMover = GetPlayerMovingMe())
13704 {
13705 WorldPackets::Movement::MoveSetFlag packet(disableStrafingOpcodeTable[disable]);
13706 packet.MoverGUID = GetGUID();
13708 playerMover->SendDirectMessage(packet.Write());
13709
13711 moveUpdate.Status = &m_movementInfo;
13712 SendMessageToSet(moveUpdate.Write(), playerMover);
13713 }
13714
13715 return true;
13716}
13717
13719{
13721 return false;
13722
13723 if (disable)
13725 else
13727
13728 static OpcodeServer const disableJumpingOpcodeTable[2] =
13729 {
13732 };
13733
13734 if (Player* playerMover = GetPlayerMovingMe())
13735 {
13736 WorldPackets::Movement::MoveSetFlag packet(disableJumpingOpcodeTable[disable]);
13737 packet.MoverGUID = GetGUID();
13739 playerMover->SendDirectMessage(packet.Write());
13740
13742 moveUpdate.Status = &m_movementInfo;
13743 SendMessageToSet(moveUpdate.Write(), playerMover);
13744 }
13745
13746 return true;
13747}
13748
13750{
13752 return false;
13753
13754 if (enable)
13756 else
13758
13759 static constexpr OpcodeServer fullSpeedTurningOpcodeTable[2] =
13760 {
13763 };
13764
13765 if (Player* playerMover = GetPlayerMovingMe())
13766 {
13767 WorldPackets::Movement::MoveSetFlag packet(fullSpeedTurningOpcodeTable[enable]);
13768 packet.MoverGUID = GetGUID();
13770 playerMover->SendDirectMessage(packet.Write());
13771
13773 moveUpdate.Status = &m_movementInfo;
13774 SendMessageToSet(moveUpdate.Write(), playerMover);
13775 }
13776
13777 return true;
13778}
13779
13781{
13783 return false;
13784
13785 if (enable)
13787 else
13789
13790 static constexpr OpcodeServer fullSpeedPitchingOpcodeTable[2] =
13791 {
13794 };
13795
13796 if (Player* playerMover = GetPlayerMovingMe())
13797 {
13798 WorldPackets::Movement::MoveSetFlag packet(fullSpeedPitchingOpcodeTable[enable]);
13799 packet.MoverGUID = GetGUID();
13801 playerMover->SendDirectMessage(packet.Write());
13802
13804 moveUpdate.Status = &m_movementInfo;
13805 SendMessageToSet(moveUpdate.Write(), playerMover);
13806 }
13807
13808 return true;
13809}
13810
13812{
13814 return false;
13815
13816 if (enable)
13818 else
13820
13821 static constexpr OpcodeServer alwaysAllowPitchingOpcodeTable[2] =
13822 {
13825 };
13826
13827 if (Player* playerMover = GetPlayerMovingMe())
13828 {
13829 WorldPackets::Movement::MoveSetFlag packet(alwaysAllowPitchingOpcodeTable[enable]);
13830 packet.MoverGUID = GetGUID();
13832 playerMover->SendDirectMessage(packet.Write());
13833
13835 moveUpdate.Status = &m_movementInfo;
13836 SendMessageToSet(moveUpdate.Write(), playerMover);
13837 }
13838
13839 return true;
13840}
13841
13843{
13844 if (GetTypeId() != TYPEID_PLAYER)
13845 return false;
13846
13848 return false;
13849
13850 if (enable)
13852 else
13854
13855 static OpcodeServer const swimToFlyTransOpcodeTable[2] =
13856 {
13859 };
13860
13861 if (Player* playerMover = GetPlayerMovingMe())
13862 {
13863 WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]);
13864 packet.MoverGUID = GetGUID();
13866 playerMover->SendDirectMessage(packet.Write());
13867
13869 moveUpdate.Status = &m_movementInfo;
13870 SendMessageToSet(moveUpdate.Write(), playerMover);
13871 }
13872
13873 return true;
13874}
13875
13877{
13878 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13879 //if (enable == HasExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING))
13880 // return false;
13881
13882 if (enable)
13884 else
13886
13887 static OpcodeServer const canTurnWhileFallingOpcodeTable[2] =
13888 {
13891 };
13892
13893 if (Player* playerMover = GetPlayerMovingMe())
13894 {
13895 WorldPackets::Movement::MoveSetFlag packet(canTurnWhileFallingOpcodeTable[enable]);
13896 packet.MoverGUID = GetGUID();
13898 playerMover->SendDirectMessage(packet.Write());
13899
13901 moveUpdate.Status = &m_movementInfo;
13902 SendMessageToSet(moveUpdate.Write(), playerMover);
13903 }
13904
13905 return true;
13906}
13907
13908bool Unit::SetCanDoubleJump(bool enable)
13909{
13911 return false;
13912
13913 if (enable)
13915 else
13917
13918 static OpcodeServer const doubleJumpOpcodeTable[2] =
13919 {
13922 };
13923
13924 if (Player* playerMover = GetPlayerMovingMe())
13925 {
13926 WorldPackets::Movement::MoveSetFlag packet(doubleJumpOpcodeTable[enable]);
13927 packet.MoverGUID = GetGUID();
13929 playerMover->SendDirectMessage(packet.Write());
13930
13932 moveUpdate.Status = &m_movementInfo;
13933 SendMessageToSet(moveUpdate.Write(), playerMover);
13934 }
13935
13936 return true;
13937}
13938
13939bool Unit::SetDisableInertia(bool disable)
13940{
13942 return false;
13943
13944 if (disable)
13946 else
13948
13949 static OpcodeServer const disableInertiaOpcodeTable[2] =
13950 {
13953 };
13954
13955 if (Player* playerMover = GetPlayerMovingMe())
13956 {
13957 WorldPackets::Movement::MoveSetFlag packet(disableInertiaOpcodeTable[disable]);
13958 packet.MoverGUID = GetGUID();
13960 playerMover->SendDirectMessage(packet.Write());
13961
13963 moveUpdate.Status = &m_movementInfo;
13964 SendMessageToSet(moveUpdate.Write(), playerMover);
13965 }
13966
13967 return true;
13968}
13969
13970bool Unit::SetCanAdvFly(bool enable)
13971{
13973 return false;
13974
13975 if (enable)
13977 else
13979
13980 static OpcodeServer const advFlyOpcodeTable[2] =
13981 {
13984 };
13985
13986 if (Player* playerMover = GetPlayerMovingMe())
13987 {
13988 WorldPackets::Movement::MoveSetFlag packet(advFlyOpcodeTable[enable]);
13989 packet.MoverGUID = GetGUID();
13991 playerMover->SendDirectMessage(packet.Write());
13992
13994 moveUpdate.Status = &m_movementInfo;
13995 SendMessageToSet(moveUpdate.Write(), playerMover);
13996 }
13997
13998 return true;
13999}
14000
14001bool Unit::SetMoveCantSwim(bool cantSwim)
14002{
14004 return false;
14005
14006 if (cantSwim)
14008 else
14010
14011 static OpcodeServer const cantSwimOpcodeTable[2] =
14012 {
14015 };
14016
14017 if (Player* playerMover = GetPlayerMovingMe())
14018 {
14019 WorldPackets::Movement::MoveSetFlag packet(cantSwimOpcodeTable[cantSwim]);
14020 packet.MoverGUID = GetGUID();
14022 playerMover->SendDirectMessage(packet.Write());
14023
14025 moveUpdate.Status = &m_movementInfo;
14026 SendMessageToSet(moveUpdate.Write(), playerMover);
14027 }
14028
14029 return true;
14030}
14031
14033{
14034 if (Player* player = ToPlayer())
14035 {
14037 moveSetVehicleRec.MoverGUID = GetGUID();
14038 moveSetVehicleRec.SequenceIndex = m_movementCounter++;
14039 moveSetVehicleRec.VehicleRecID = vehicleId;
14040 player->SendDirectMessage(moveSetVehicleRec.Write());
14041 }
14042
14044 setVehicleRec.VehicleGUID = GetGUID();
14045 setVehicleRec.VehicleRecID = vehicleId;
14046 SendMessageToSet(setVehicleRec.Write(), true);
14047}
14048
14049void Unit::ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction /*= {}*/, ObjectGuid transportGuid /*= ObjectGuid::Empty*/)
14050{
14051 if (!_movementForces)
14052 _movementForces = std::make_unique<MovementForces>();
14053
14054 MovementForce force;
14055 force.ID = id;
14056 force.Origin = origin;
14057 force.Direction = direction;
14058 if (transportGuid.IsMOTransport())
14059 force.TransportID = transportGuid.GetCounter();
14060
14061 force.Magnitude = magnitude;
14062 force.Type = type;
14063
14064 if (_movementForces->Add(force))
14065 {
14066 if (Player const* movingPlayer = GetPlayerMovingMe())
14067 {
14069 applyMovementForce.MoverGUID = GetGUID();
14070 applyMovementForce.SequenceIndex = m_movementCounter++;
14071 applyMovementForce.Force = &force;
14072 movingPlayer->SendDirectMessage(applyMovementForce.Write());
14073 }
14074 else
14075 {
14077 updateApplyMovementForce.Status = &m_movementInfo;
14078 updateApplyMovementForce.Force = &force;
14079 SendMessageToSet(updateApplyMovementForce.Write(), true);
14080 }
14081 }
14082}
14083
14085{
14086 if (!_movementForces)
14087 return;
14088
14089 if (_movementForces->Remove(id))
14090 {
14091 if (Player const* movingPlayer = GetPlayerMovingMe())
14092 {
14094 moveRemoveMovementForce.MoverGUID = GetGUID();
14095 moveRemoveMovementForce.SequenceIndex = m_movementCounter++;
14096 moveRemoveMovementForce.ID = id;
14097 movingPlayer->SendDirectMessage(moveRemoveMovementForce.Write());
14098 }
14099 else
14100 {
14102 updateRemoveMovementForce.Status = &m_movementInfo;
14103 updateRemoveMovementForce.TriggerGUID = id;
14104 SendMessageToSet(updateRemoveMovementForce.Write(), true);
14105 }
14106 }
14107
14108 if (_movementForces->IsEmpty())
14109 _movementForces.reset();
14110}
14111
14113{
14115 return false;
14116
14117 if (ignore)
14119 else
14121
14122 static OpcodeServer const ignoreMovementForcesOpcodeTable[2] =
14123 {
14126 };
14127
14128 if (Player const* movingPlayer = GetPlayerMovingMe())
14129 {
14130 WorldPackets::Movement::MoveSetFlag packet(ignoreMovementForcesOpcodeTable[ignore]);
14131 packet.MoverGUID = GetGUID();
14133 movingPlayer->SendDirectMessage(packet.Write());
14134
14136 moveUpdate.Status = &m_movementInfo;
14137 SendMessageToSet(moveUpdate.Write(), movingPlayer);
14138 }
14139
14140 return true;
14141}
14142
14144{
14146
14147 if (Player* movingPlayer = GetPlayerMovingMe())
14148 {
14150 setModMovementForceMagnitude.MoverGUID = GetGUID();
14151 setModMovementForceMagnitude.SequenceIndex = m_movementCounter++;
14152 setModMovementForceMagnitude.Speed = modMagnitude;
14153 movingPlayer->SendDirectMessage(setModMovementForceMagnitude.Write());
14154 ++movingPlayer->m_movementForceModMagnitudeChanges;
14155 }
14156 else
14157 {
14159 updateModMovementForceMagnitude.Status = &m_movementInfo;
14160 updateModMovementForceMagnitude.Speed = modMagnitude;
14161 SendMessageToSet(updateModMovementForceMagnitude.Write(), true);
14162 }
14163
14164 if (modMagnitude != 1.0f && !_movementForces)
14165 _movementForces = std::make_unique<MovementForces>();
14166
14167 if (_movementForces)
14168 {
14169 _movementForces->SetModMagnitude(modMagnitude);
14170 if (_movementForces->IsEmpty())
14171 _movementForces.reset();
14172 }
14173}
14174
14175void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
14176{
14177 if (IsPlayingHoverAnim() == enable)
14178 return;
14179
14180 m_updateFlag.PlayHoverAnim = enable;
14181
14182 if (!sendUpdate)
14183 return;
14184
14186 data.UnitGUID = GetGUID();
14187 data.PlayHoverAnim = enable;
14188
14189 SendMessageToSet(data.Write(), true);
14190}
14191
14193{
14194 float hoverHeight = DEFAULT_PLAYER_HOVER_HEIGHT;
14195 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
14196
14197 uint32 displayId = IsMounted() ? GetMountDisplayId() : GetDisplayId();
14198
14199 // Get DisplayScale for creatures
14200 if (IsCreature())
14201 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
14202 displayScale = model->DisplayScale;
14203
14204 if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(displayId))
14205 if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelID))
14206 hoverHeight = modelData->HoverHeight * modelData->ModelScale * displayInfo->CreatureModelScale * displayScale;
14207
14208 SetHoverHeight(hoverHeight ? hoverHeight : DEFAULT_PLAYER_HOVER_HEIGHT);
14209}
14210
14212{
14213 return movespline->Initialized() && !movespline->Finalized();
14214}
14215
14217{
14219 if (target == this || GetOwnerGUID() == target->GetGUID())
14221
14225
14226 return flags;
14227}
14228
14229void Unit::DestroyForPlayer(Player const* target) const
14230{
14231 if (Battleground* bg = target->GetBattleground())
14232 {
14233 if (bg->isArena())
14234 {
14236 destroyArenaUnit.Guid = GetGUID();
14237 target->GetSession()->SendPacket(destroyArenaUnit.Write());
14238 }
14239 }
14240
14242}
14243
14249
14250SpellEffectValue Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
14251{
14252 SpellEffectValue val = 0;
14253 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
14254 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
14255 {
14256 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
14257 {
14258 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
14259 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
14260 {
14261 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
14262 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
14263 {
14264 // absolute value only
14265 if (abs(val) < abs((*auraItr)->GetAmount()))
14266 val = (*auraItr)->GetAmount();
14267 }
14268 }
14269 }
14270 }
14271 return val;
14272}
14273
14274bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
14275{
14276 for (AuraEffect const* aurEff : aura->GetAuraEffects())
14277 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
14278 return false;
14279
14280 return true;
14281}
14282
14283bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, SpellEffectValue effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
14284{
14285 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
14286 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
14287 {
14288 AuraEffect const* existingAurEff = (*itr);
14289 ++itr;
14290
14291 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
14292 {
14293 SpellEffectValue diff = abs(effectAmount) - abs(existingAurEff->GetAmount());
14294 if (!diff)
14295 {
14296 // treat the aura with more effects as stronger
14297 diff = std::popcount(auraEffectMask) - std::popcount(existingAurEff->GetBase()->GetEffectMask());
14298 }
14299
14300 if (diff > 0)
14301 {
14302 Aura const* base = existingAurEff->GetBase();
14303 // no removing of area auras from the original owner, as that completely cancels them
14304 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
14305 {
14306 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
14307 {
14308 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
14309 uint32 removedAuras = m_removedAurasCount;
14310 RemoveAura(aurApp);
14311 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
14312 itr = auras.begin();
14313 }
14314 }
14315 }
14316 else if (diff < 0)
14317 return false;
14318 }
14319 }
14320
14321 return true;
14322}
14323
14324void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
14325{
14326 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
14329 Cell::VisitWorldObjects(this, worker, textRange);
14330}
14331
14332void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
14333{
14334 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
14335}
14336
14337void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
14338{
14339 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
14340}
14341
14342void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
14343{
14345}
14346
14347void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
14348{
14349 if (!target)
14350 return;
14351
14354 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
14355 target->SendDirectMessage(packet.Write());
14356}
14357
14359{
14360 if (slot >= MAX_EQUIPMENT_ITEMS)
14361 return 0;
14362
14363 return m_unitData->VirtualItems[slot].ItemID;
14364}
14365
14367{
14368 if (slot >= MAX_EQUIPMENT_ITEMS)
14369 return 0;
14370
14371 return m_unitData->VirtualItems[slot].ItemAppearanceModID;
14372}
14373
14374void Unit::SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId /*= 0*/, uint16 itemVisual /*= 0*/)
14375{
14376 if (slot >= MAX_EQUIPMENT_ITEMS)
14377 return;
14378
14379 auto virtualItemField = m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::VirtualItems, slot);
14380 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemID), itemId);
14381 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), appearanceModId);
14382 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemVisual), itemVisual);
14383}
14384
14385void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
14386{
14387 if (!sBroadcastTextStore.LookupEntry(textId))
14388 {
14389 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
14390 return;
14391 }
14392
14393 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
14396 Cell::VisitWorldObjects(this, worker, textRange);
14397}
14398
14399void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
14400{
14401 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
14402}
14403
14404void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
14405{
14406 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
14407}
14408
14409void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
14410{
14411 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
14412}
14413
14414void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
14415{
14416 if (!target)
14417 return;
14418
14419 BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(textId);
14420 if (!bct)
14421 {
14422 TC_LOG_ERROR("entities.unit", "WorldObject::Whisper: `broadcast_text` was not {} found", textId);
14423 return;
14424 }
14425
14428 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, GetGender()), 0, "", locale);
14429 target->SendDirectMessage(packet.Write());
14430}
14431
14432void Unit::ClearBossEmotes(Optional<uint32> zoneId, Player const* target) const
14433{
14435 clearBossEmotes.Write();
14436
14437 if (target)
14438 {
14439 target->SendDirectMessage(clearBossEmotes.GetRawPacket());
14440 return;
14441 }
14442
14443 for (MapReference const& ref : GetMap()->GetPlayers())
14444 if (!zoneId || DB2Manager::IsInArea(ref.GetSource()->GetAreaId(), *zoneId))
14445 ref.GetSource()->SendDirectMessage(clearBossEmotes.GetRawPacket());
14446}
14447
14449{
14450 for (uint32& slot : VisitedSpells)
14451 {
14452 if (slot == spellId)
14453 return false; // already exists
14454
14455 if (!slot)
14456 {
14457 slot = spellId;
14458 return true;
14459 }
14460 }
14461
14462 return false; // no free slots left
14463}
14464
14465SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag, GetCastSpellInfoContext* context) const
14466{
14467 auto findMatchingAuraEffectIn = [this, spellInfo, &triggerFlag, context](AuraType type) -> SpellInfo const*
14468 {
14469 for (AuraEffect const* auraEffect : GetAuraEffectsByType(type))
14470 {
14471 bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo);
14472 if (matches && context->AddSpell(auraEffect->GetAmountAsInt()))
14473 {
14474 if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmountAsInt(), GetMap()->GetDifficultyID()))
14475 {
14476 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
14477 triggerFlag |= TRIGGERED_IGNORE_POWER_COST;
14478 else
14479 triggerFlag &= ~TRIGGERED_IGNORE_POWER_COST;
14480
14481 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR11_IGNORE_SPELLCAST_OVERRIDE_SHAPESHIFT_REQUIREMENTS))
14482 triggerFlag |= TRIGGERED_IGNORE_SHAPESHIFT;
14483 else
14484 triggerFlag &= ~TRIGGERED_IGNORE_SHAPESHIFT;
14485
14486 return newInfo;
14487 }
14488 }
14489 }
14490
14491 return nullptr;
14492 };
14493
14494 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS))
14495 {
14496 triggerFlag &= ~TRIGGERED_IGNORE_CAST_TIME;
14497 return GetCastSpellInfo(newInfo, triggerFlag, context);
14498 }
14499
14500 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED))
14501 {
14502 triggerFlag |= TRIGGERED_IGNORE_CAST_TIME;
14503 return GetCastSpellInfo(newInfo, triggerFlag, context);
14504 }
14505
14506 return spellInfo;
14507}
14508
14510{
14512 for (AuraEffect const* effect : visualOverrides)
14513 {
14514 if (uint32(effect->GetMiscValue()) == spellInfo->Id)
14515 {
14516 if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB(), GetMap()->GetDifficultyID()))
14517 {
14518 spellInfo = visualSpell;
14519 break;
14520 }
14521 }
14522 }
14523
14525}
14526
14528{
14529 return left->GetSlot() < right->GetSlot();
14530}
14531
14532// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
14534{
14535 float scaleMod = GetObjectScale(); // 99% sure about this
14536
14537 if (IsMounted())
14538 {
14539 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
14540 {
14541 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
14542 {
14543 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14544 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14545 float const collisionHeight = scaleMod * ((mountModelData->MountHeight * mountDisplayInfo->CreatureModelScale) + (modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f));
14546 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14547 }
14548 }
14549 }
14550
14552 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14553 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14554
14555 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
14556 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14557}
14558
14559void Unit::AddWorldEffect(int32 worldEffectId)
14560{
14562}
14563
14565{
14566 int32 index = m_unitData->WorldEffects.FindIndex(worldEffectId);
14567 if (index >= 0)
14569}
14570
14575
14577{
14578 if (m_vignette)
14579 {
14580 if (m_vignette->Data->ID == vignetteId)
14581 return;
14582
14584 m_vignette = nullptr;
14585 }
14586
14587 if (VignetteEntry const* vignette = sVignetteStore.LookupEntry(vignetteId))
14588 m_vignette = Vignettes::Create(vignette, this);
14589}
14590
14591std::string Unit::GetDebugInfo() const
14592{
14593 std::stringstream sstr;
14594 sstr << WorldObject::GetDebugInfo() << "\n"
14595 << std::boolalpha
14596 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
14597 << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
14598 << " Class: " << std::to_string(GetClass()) << "\n"
14599 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
14600 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
14601 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
14602 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
14603 << "m_Controlled size: " << m_Controlled.size();
14604
14605 size_t controlledCount = 0;
14606 for (Unit* controlled : m_Controlled)
14607 {
14608 ++controlledCount;
14609 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
14610 }
14611
14612 return sstr.str();
14613}
14614
14616{
14617 for (std::size_t i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
14618 name[i] = uf.Name[i];
14619}
#define sBattlefieldMgr
@ SCORE_DAMAGE_DONE
@ SCORE_HEALING_DONE
#define sCharacterCache
CharmType
Definition CharmInfo.h:68
@ CHARM_TYPE_CHARM
Definition CharmInfo.h:69
@ CHARM_TYPE_POSSESS
Definition CharmInfo.h:70
@ CHARM_TYPE_CONVERT
Definition CharmInfo.h:72
@ CHARM_TYPE_VEHICLE
Definition CharmInfo.h:71
LocaleConstant
Definition Common.h:51
@ IN_MILLISECONDS
Definition Common.h:38
@ MINUTE
Definition Common.h:32
@ SEC_PLAYER
Definition Common.h:43
@ SEC_GAMEMASTER
Definition Common.h:45
#define M_PI
Definition Common.h:118
#define sConditionMgr
#define sCreatureAIRegistry
@ CREATURE_FLAG_EXTRA_NO_BLOCK
@ CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS
@ CREATURE_FLAG_EXTRA_NO_CRIT
@ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
@ CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
@ CREATURE_FLAG_EXTRA_NO_PARRY
@ CREATURE_STATIC_FLAG_UNKILLABLE
DB2Storage< ArtifactAppearanceEntry > sArtifactAppearanceStore("ArtifactAppearance.db2", &ArtifactAppearanceLoadInfo::Instance)
DB2Storage< SpellCategoryEntry > sSpellCategoryStore("SpellCategory.db2", &SpellCategoryLoadInfo::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:569
AreaMountFlags
Definition DBCEnums.h:163
@ AllowUnderwaterSwimmingMounts
@ AllowSurfaceSwimmingMounts
#define MAX_EFFECT_MASK
Definition DBCEnums.h:2431
@ ArmorItemLevelDiminishing
@ UnitsUseDefaultPowerOnInit
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
@ MOUNT_CAPABILITY_FLAG_FLYING
Definition DBCEnums.h:2103
@ MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS
Definition DBCEnums.h:2106
@ MOUNT_CAPABILITY_FLAG_UNDERWATER
Definition DBCEnums.h:2105
@ MOUNT_CAPABILITY_FLAG_GROUND
Definition DBCEnums.h:2102
@ MOUNT_CAPABILITY_FLAG_FLOAT
Definition DBCEnums.h:2104
#define TC_GAME_API
Definition Define.h:129
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
uint16 flags
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:88
#define ABORT
Definition Errors.h:87
#define ASSERT_NODEBUGINFO
Definition Errors.h:81
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:82
#define ASSERT
Definition Errors.h:80
GameTable< GtItemLevelByLevelEntry > sItemLevelByLevelTable
@ 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
@ ITEM_SUBCLASS_WEAPON_AXE2
@ ITEM_SUBCLASS_WEAPON_STAFF
@ ITEM_SUBCLASS_WEAPON_MACE
@ ITEM_SUBCLASS_WEAPON_EXOTIC2
@ ITEM_SUBCLASS_WEAPON_WARGLAIVES
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
@ ITEM_SUBCLASS_WEAPON_MACE2
@ ITEM_SUBCLASS_WEAPON_DAGGER
@ ITEM_SUBCLASS_WEAPON_SWORD
@ ITEM_SUBCLASS_WEAPON_AXE
@ ITEM_SUBCLASS_WEAPON_FIST_WEAPON
@ ITEM_SUBCLASS_WEAPON_EXOTIC
@ ITEM_SUBCLASS_WEAPON_THROWN
@ ITEM_SUBCLASS_WEAPON_SWORD2
@ ITEM_SUBCLASS_WEAPON_POLEARM
@ INVTYPE_SHIELD
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_FATAL(filterType__, message__,...)
Definition Log.h:193
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:133
@ LIQUID_MAP_UNDER_WATER
Definition MapDefines.h:138
@ LIQUID_MAP_OCEAN_FLOOR
Definition MapDefines.h:139
@ LIQUID_MAP_IN_WATER
Definition MapDefines.h:137
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
#define DEFAULT_PLAYER_HOVER_HEIGHT
#define DEFAULT_PLAYER_DISPLAY_SCALE
#define NOMINAL_MELEE_RANGE
#define MIN_MELEE_REACH
@ NOTIFY_VISIBILITY_CHANGED
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:46
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
#define sObjectMgr
Definition ObjectMgr.h:1885
float const DEFAULT_COLLISION_HEIGHT
Definition Object.h:78
OpcodeServer
Definition Opcodes.h:1085
@ SMSG_MOVE_SPLINE_SET_PITCH_RATE
Definition Opcodes.h:1935
@ SMSG_MOVE_SET_ADV_FLYING_LAUNCH_SPEED_COEFFICIENT
Definition Opcodes.h:1888
@ SMSG_MOVE_SPLINE_SET_SWIM_SPEED
Definition Opcodes.h:1940
@ SMSG_MOVE_SET_FLIGHT_SPEED
Definition Opcodes.h:1906
@ SMSG_MOVE_SPLINE_SET_FLYING
Definition Opcodes.h:1931
@ SMSG_MOVE_SET_FLIGHT_BACK_SPEED
Definition Opcodes.h:1905
@ SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION
Definition Opcodes.h:1894
@ SMSG_MOVE_DISABLE_COLLISION
Definition Opcodes.h:1858
@ SMSG_MOVE_UPDATE_PITCH_RATE
Definition Opcodes.h:1969
@ SMSG_MOVE_SPLINE_SET_WALK_SPEED
Definition Opcodes.h:1943
@ SMSG_MOVE_ENABLE_DOUBLE_JUMP
Definition Opcodes.h:1868
@ SMSG_MOVE_ROOT
Definition Opcodes.h:1881
@ SMSG_MOVE_SPLINE_SET_RUN_MODE
Definition Opcodes.h:1937
@ SMSG_MOVE_DISABLE_GRAVITY
Definition Opcodes.h:1862
@ SMSG_MOVE_UNSET_CANNOT_SWIM
Definition Opcodes.h:1953
@ SMSG_MOVE_SPLINE_SET_SWIM_BACK_SPEED
Definition Opcodes.h:1939
@ SMSG_MOVE_SPLINE_DISABLE_COLLISION
Definition Opcodes.h:1923
@ SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition Opcodes.h:1875
@ SMSG_MOVE_UNROOT
Definition Opcodes.h:1951
@ SMSG_MOVE_SPLINE_UNROOT
Definition Opcodes.h:1947
@ SMSG_MOVE_SET_RUN_BACK_SPEED
Definition Opcodes.h:1914
@ SMSG_MOVE_SPLINE_SET_HOVER
Definition Opcodes.h:1932
@ SMSG_MOVE_SPLINE_SET_WATER_WALK
Definition Opcodes.h:1944
@ SMSG_MOVE_ENABLE_FULL_SPEED_PITCHING
Definition Opcodes.h:1869
@ SMSG_MOVE_SPLINE_SET_NORMAL_FALL
Definition Opcodes.h:1934
@ SMSG_MOVE_ENABLE_INERTIA
Definition Opcodes.h:1872
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_DOWN
Definition Opcodes.h:1892
@ SMSG_MOVE_SPLINE_SET_TURN_RATE
Definition Opcodes.h:1941
@ SMSG_MOVE_SET_NORMAL_FALL
Definition Opcodes.h:1912
@ SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE
Definition Opcodes.h:1885
@ SMSG_MOVE_SET_ADV_FLYING_LIFT_COEFFICIENT
Definition Opcodes.h:1889
@ SMSG_MOVE_SPLINE_UNSET_HOVER
Definition Opcodes.h:1949
@ SMSG_MOVE_UPDATE_FLIGHT_SPEED
Definition Opcodes.h:1966
@ SMSG_MOVE_SET_PITCH_RATE
Definition Opcodes.h:1913
@ SMSG_MOVE_SPLINE_SET_LAND_WALK
Definition Opcodes.h:1933
@ SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED
Definition Opcodes.h:1965
@ SMSG_MOVE_UPDATE_WALK_SPEED
Definition Opcodes.h:1979
@ SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING
Definition Opcodes.h:1901
@ SMSG_MOVE_SPLINE_DISABLE_GRAVITY
Definition Opcodes.h:1924
@ SMSG_MOVE_ENABLE_COLLISION
Definition Opcodes.h:1867
@ SMSG_MOVE_SET_IGNORE_MOVEMENT_FORCES
Definition Opcodes.h:1909
@ SMSG_MOVE_DISABLE_STRAFING
Definition Opcodes.h:1865
@ SMSG_MOVE_DISABLE_FULL_SPEED_TURNING
Definition Opcodes.h:1861
@ SMSG_MOVE_UNSET_IGNORE_MOVEMENT_FORCES
Definition Opcodes.h:1959
@ SMSG_MOVE_UPDATE_SWIM_SPEED
Definition Opcodes.h:1976
@ SMSG_MOVE_ENABLE_GRAVITY
Definition Opcodes.h:1871
@ SMSG_MOVE_UPDATE_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition Opcodes.h:1968
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP
Definition Opcodes.h:1893
@ SMSG_MOVE_SET_ADV_FLYING_OVER_MAX_DECELERATION
Definition Opcodes.h:1891
@ SMSG_MOVE_SET_ADV_FLYING_MAX_VEL
Definition Opcodes.h:1890
@ SMSG_MOVE_UNSET_HOVERING
Definition Opcodes.h:1958
@ SMSG_MOVE_UNSET_CAN_ADV_FLY
Definition Opcodes.h:1954
@ SMSG_MOVE_UPDATE_TURN_RATE
Definition Opcodes.h:1978
@ SMSG_MOVE_SPLINE_SET_RUN_BACK_SPEED
Definition Opcodes.h:1936
@ SMSG_MOVE_SET_TURN_RATE
Definition Opcodes.h:1918
@ SMSG_MOVE_SET_WATER_WALK
Definition Opcodes.h:1921
@ SMSG_MOVE_SPLINE_ROOT
Definition Opcodes.h:1927
@ SMSG_MOVE_UNSET_ALWAYS_ALLOW_PITCHING
Definition Opcodes.h:1952
@ SMSG_MOVE_SET_CANNOT_SWIM
Definition Opcodes.h:1897
@ SMSG_MOVE_SET_ALWAYS_ALLOW_PITCHING
Definition Opcodes.h:1896
@ SMSG_MOVE_SET_SWIM_SPEED
Definition Opcodes.h:1917
@ SMSG_MOVE_UPDATE_RUN_SPEED
Definition Opcodes.h:1973
@ SMSG_MOVE_SET_WALK_SPEED
Definition Opcodes.h:1920
@ SMSG_MOVE_SET_HOVERING
Definition Opcodes.h:1908
@ SMSG_MOVE_SET_ADV_FLYING_ADD_IMPULSE_MAX_SPEED
Definition Opcodes.h:1883
@ SMSG_MOVE_ENABLE_FULL_SPEED_TURNING
Definition Opcodes.h:1870
@ SMSG_MOVE_SET_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition Opcodes.h:1911
@ SMSG_MOVE_SET_ADV_FLYING_GLIDE_START_MIN_HEIGHT
Definition Opcodes.h:1887
@ SMSG_MOVE_SPLINE_ENABLE_GRAVITY
Definition Opcodes.h:1926
@ SMSG_MOVE_SET_CAN_FLY
Definition Opcodes.h:1900
@ SMSG_MOVE_SPLINE_SET_RUN_SPEED
Definition Opcodes.h:1938
@ SMSG_MOVE_DISABLE_INERTIA
Definition Opcodes.h:1863
@ SMSG_MOVE_SET_CAN_ADV_FLY
Definition Opcodes.h:1898
@ SMSG_MOVE_SPLINE_SET_FLIGHT_BACK_SPEED
Definition Opcodes.h:1929
@ SMSG_MOVE_UPDATE_SWIM_BACK_SPEED
Definition Opcodes.h:1975
@ SMSG_MOVE_DISABLE_DOUBLE_JUMP
Definition Opcodes.h:1859
@ SMSG_MOVE_DISABLE_FULL_SPEED_PITCHING
Definition Opcodes.h:1860
@ SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD
Definition Opcodes.h:1895
@ SMSG_MOVE_UNSET_CAN_FLY
Definition Opcodes.h:1956
@ SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD
Definition Opcodes.h:1886
@ SMSG_MOVE_SPLINE_UNSET_FLYING
Definition Opcodes.h:1948
@ SMSG_MOVE_SPLINE_SET_FLIGHT_SPEED
Definition Opcodes.h:1930
@ SMSG_MOVE_SPLINE_STOP_SWIM
Definition Opcodes.h:1946
@ SMSG_MOVE_SPLINE_START_SWIM
Definition Opcodes.h:1945
@ SMSG_MOVE_UPDATE_RUN_BACK_SPEED
Definition Opcodes.h:1972
@ SMSG_MOVE_SET_SWIM_BACK_SPEED
Definition Opcodes.h:1916
@ SMSG_MOVE_UNSET_CAN_TURN_WHILE_FALLING
Definition Opcodes.h:1957
@ SMSG_MOVE_SET_RUN_SPEED
Definition Opcodes.h:1915
@ SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition Opcodes.h:1866
@ SMSG_MOVE_SPLINE_ENABLE_COLLISION
Definition Opcodes.h:1925
@ SMSG_MOVE_ENABLE_STRAFING
Definition Opcodes.h:1874
@ SMSG_MOVE_SET_ADV_FLYING_AIR_FRICTION
Definition Opcodes.h:1884
@ SMSG_MOVE_SET_LAND_WALK
Definition Opcodes.h:1910
@ SMSG_MOVE_DISABLE_JUMPING
Definition Opcodes.h:1864
@ SMSG_MOVE_SPLINE_SET_FEATHER_FALL
Definition Opcodes.h:1928
@ SMSG_MOVE_SPLINE_SET_WALK_MODE
Definition Opcodes.h:1942
@ SMSG_MOVE_SET_FEATHER_FALL
Definition Opcodes.h:1904
@ SMSG_MOVE_ENABLE_JUMPING
Definition Opcodes.h:1873
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:727
@ EQUIPMENT_SLOT_END
Definition Player.h:748
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:745
@ TELE_TO_SPELL
Definition Player.h:927
@ TELE_TO_NOT_LEAVE_COMBAT
Definition Player.h:925
@ TELE_TO_NOT_UNSUMMON_PET
Definition Player.h:926
@ TELE_TO_NONE
Definition Player.h:922
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition Player.h:924
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition Player.h:352
@ CHEAT_GOD
Definition Player.h:1076
@ PLAYERSPELL_REMOVED
Definition Player.h:209
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition Player.h:3449
Races
Definition RaceMask.h:27
float rand_norm()
Definition Random.cpp:75
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
bool roll_chance(T chance)
Definition Random.h:55
#define sScriptMgr
Definition ScriptMgr.h:1449
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ SPELL_ATTR11_IGNORE_SPELLCAST_OVERRIDE_SHAPESHIFT_REQUIREMENTS
@ SPELL_ATTR11_IGNORE_CASTER_ABSORB_MODIFIERS
@ SPELL_ATTR11_IGNORE_TARGET_ABSORB_MODIFIERS
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ 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_WARLOCK
@ CLASS_MAGE
@ CLASS_NONE
@ CLASS_ROGUE
Language
@ LANG_UNIVERSAL
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
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_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_SPIRIT
@ 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
@ 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_DISABLE_AUTOATTACK
@ 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_ABSORB_DONE_PCT
@ 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_ABSORB_TAKEN_PCT
@ 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
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
SpellAuraInterruptFlags2
@ PeriodicHealingAndDamage
@ CritDamageAndHealing
TriggerCastFlags
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
@ TRIGGERED_IGNORE_SHAPESHIFT
Will ignore shapeshift checks.
@ TRIGGERED_IGNORE_POWER_COST
Will ignore power and reagent cost.
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
@ TRIGGERED_NONE
Not triggered.
@ TRIGGERED_IGNORE_CAST_TIME
Will always be instantly cast.
SpellValueModFloat
@ SPELLVALUE_BASE_POINT0
SpellAuraInterruptFlags
std::vector< AuraEffect * > AuraEffectVector
Definition SpellInfo.h:305
@ 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:201
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:337
ProcFlagsSpellPhase
Definition SpellMgr.h:222
@ PROC_SPELL_PHASE_NONE
Definition SpellMgr.h:223
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:225
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:348
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition SpellMgr.h:349
#define sSpellMgr
Definition SpellMgr.h:812
ProcFlagsSpellType
Definition SpellMgr.h:211
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:212
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:216
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:213
@ PROC_FLAG_MAIN_HAND_WEAPON_SWING
Definition SpellMgr.h:128
@ PROC_FLAG_TAKE_MELEE_SWING
Definition SpellMgr.h:98
@ PROC_FLAG_TAKE_ANY_DAMAGE
Definition SpellMgr.h:124
@ PROC_FLAG_ENCOUNTER_START
Definition SpellMgr.h:139
@ PROC_FLAG_DEAL_MELEE_SWING
Definition SpellMgr.h:97
@ PROC_FLAG_HEARTBEAT
Definition SpellMgr.h:94
@ PROC_FLAG_TAKE_HARMFUL_SPELL
Definition SpellMgr.h:119
@ PROC_FLAG_DEATH
Definition SpellMgr.h:131
@ PROC_FLAG_OFF_HAND_WEAPON_SWING
Definition SpellMgr.h:129
@ PROC_FLAG_ENTER_COMBAT
Definition SpellMgr.h:137
@ PROC_FLAG_KILL
Definition SpellMgr.h:95
@ PROC_FLAG_NONE
Definition SpellMgr.h:92
@ PROC_FLAG_2_TARGET_DIES
Definition SpellMgr.h:190
ProcFlagsHit
Definition SpellMgr.h:233
@ PROC_HIT_BLOCK
Definition SpellMgr.h:241
@ PROC_HIT_FULL_RESIST
Definition SpellMgr.h:238
@ PROC_HIT_FULL_BLOCK
Definition SpellMgr.h:248
@ PROC_HIT_MISS
Definition SpellMgr.h:237
@ PROC_HIT_NONE
Definition SpellMgr.h:234
@ PROC_HIT_DEFLECT
Definition SpellMgr.h:244
@ PROC_HIT_EVADE
Definition SpellMgr.h:242
@ PROC_HIT_DODGE
Definition SpellMgr.h:239
@ PROC_HIT_IMMUNE
Definition SpellMgr.h:243
@ PROC_HIT_ABSORB
Definition SpellMgr.h:245
@ PROC_HIT_PARRY
Definition SpellMgr.h:240
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:236
@ PROC_HIT_NORMAL
Definition SpellMgr.h:235
@ PROC_HIT_REFLECT
Definition SpellMgr.h:246
SpellOtherImmunity
Definition SpellMgr.h:555
@ SPELL_CAST_SOURCE_NORMAL
Definition Spell.h:168
@ SPELL_STATE_CHANNELING
Definition Spell.h:259
@ SPELL_STATE_FINISHED
Definition Spell.h:260
@ SPELL_STATE_PREPARING
Definition Spell.h:257
@ SPELL_STATE_LAUNCHED
Definition Spell.h:258
@ SPELL_STATE_IDLE
Definition Spell.h:261
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ TOTEM_PASSIVE
Definition Totem.h:25
UnitMoveType
@ MOVE_FLIGHT
@ MOVE_SWIM
@ MOVE_FLIGHT_BACK
@ MOVE_SWIM_BACK
@ MOVE_RUN
@ MOVE_RUN_BACK
@ MOVE_WALK
@ UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS
@ UNIT_FLAG2_INTERACT_WHILE_HOSTILE
@ UNIT_FLAG2_CANNOT_TURN
@ UNIT_FLAG2_DISARM_OFFHAND
@ UNIT_FLAG2_DISARM_RANGED
HitInfo
@ HITINFO_PARTIAL_ABSORB
@ HITINFO_FULL_RESIST
@ HITINFO_NORMALSWING
@ HITINFO_BLOCK
@ HITINFO_CRUSHING
@ HITINFO_FAKE_DAMAGE
@ HITINFO_SWINGNOHITSOUND
@ HITINFO_MISS
@ HITINFO_RAGE_GAIN
@ HITINFO_FULL_ABSORB
@ HITINFO_NO_ANIMATION
@ HITINFO_OFFHAND
@ HITINFO_GLANCING
@ HITINFO_CRITICALHIT
@ HITINFO_PARTIAL_RESIST
@ HITINFO_AFFECTS_VICTIM
@ REACT_PASSIVE
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
@ ADV_FLYING_DOUBLE_JUMP_VEL_MOD
@ ADV_FLYING_OVER_MAX_DECELERATION
@ ADV_FLYING_LIFT_COEFFICIENT
@ ADV_FLYING_ADD_IMPULSE_MAX_SPEED
@ ADV_FLYING_GLIDE_START_MIN_HEIGHT
@ ADV_FLYING_AIR_FRICTION
@ ADV_FLYING_LAUNCH_SPEED_COEFFICIENT
@ ADV_FLYING_MAX_VEL
@ ADV_FLYING_SURFACE_FRICTION
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_WATERWALKING
@ MOVEMENTFLAG_MASK_MOVING
@ MOVEMENTFLAG_DISABLE_GRAVITY
@ MOVEMENTFLAG_FALLING_SLOW
@ MOVEMENTFLAG_CAN_FLY
@ MOVEMENTFLAG_ROOT
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_MASK_MOVING_FLY
@ MOVEMENTFLAG_FALLING_FAR
@ MOVEMENTFLAG_SWIMMING
@ MOVEMENTFLAG_HOVER
@ MOVEMENTFLAG_SPLINE_ELEVATION
@ MOVEMENTFLAG_WALKING
@ MOVEMENTFLAG_DISABLE_COLLISION
#define MAX_MOVE_TYPE
@ MOVEMENTFLAG2_CAN_DOUBLE_JUMP
@ MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS
@ MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING
@ MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING
@ MOVEMENTFLAG2_NO_STRAFE
@ MOVEMENTFLAG2_IGNORE_MOVEMENT_FORCES
@ MOVEMENTFLAG2_FULL_SPEED_PITCHING
@ MOVEMENTFLAG2_FULL_SPEED_TURNING
@ MOVEMENTFLAG2_NO_JUMPING
#define MAX_DECLINED_NAME_CASES
AdvFlyingRateTypeRange
@ ADV_FLYING_PITCHING_RATE_DOWN
@ ADV_FLYING_TURN_VELOCITY_THRESHOLD
@ ADV_FLYING_PITCHING_RATE_UP
@ ADV_FLYING_BANKING_RATE
@ UNIT_NPC_FLAG_TABARDDESIGNER
@ UNIT_NPC_FLAG_SPIRIT_HEALER
@ UNIT_NPC_FLAG_BANKER
@ UNIT_NPC_FLAG_AUCTIONEER
@ UNIT_NPC_FLAG_AREA_SPIRIT_HEALER
@ UNIT_NPC_FLAG_VENDOR
@ UNIT_NPC_FLAG_BATTLEMASTER
@ UNIT_NPC_FLAG_INNKEEPER
@ UNIT_NPC_FLAG_SPELLCLICK
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
@ UNIT_NPC_FLAG_FLIGHTMASTER
@ UNIT_NPC_FLAG_TRAINER
@ UNIT_NPC_FLAG_PETITIONER
DamageEffectType
@ SELF_DAMAGE
@ DIRECT_DAMAGE
@ NODAMAGE
@ DOT
@ SPELL_DIRECT_DAMAGE
#define BASE_MAXDAMAGE
Definition UnitDefines.h:34
@ UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT
SheathState
Definition UnitDefines.h:81
@ SHEATH_STATE_UNARMED
Definition UnitDefines.h:82
@ MOVEMENTFLAG3_ADV_FLYING
@ MOVEMENTFLAG3_DISABLE_INERTIA
@ MOVEMENTFLAG3_CANNOT_SWIM
@ MOVEMENTFLAG3_CAN_ADV_FLY
#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
#define BASE_MINDAMAGE
Definition UnitDefines.h:33
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_POSSESSED
@ UNIT_FLAG_DISARMED
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_CAN_SWIM
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
@ UNIT_FLAG_FLEEING
@ UNIT_FLAG_CANT_SWIM
@ UNIT_FLAG_RENAME
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_FLAG_IMMUNE_TO_PC
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
@ UNIT_FLAG_MOUNT
@ UNIT_FLAG_PET_IN_COMBAT
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:98
bool IsInterruptFlagIgnoredForSpell(InterruptFlag, Unit const *, SpellInfo const *, bool, SpellInfo const *)
Definition Unit.cpp:4207
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:10407
static uint32 CalcMeleeAttackRageGain(Unit const *attacker, WeaponAttackType attType)
Definition Unit.cpp:2248
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition Unit.cpp:10961
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:111
UnitModifierFlatType
Definition Unit.h:155
@ BASE_VALUE
Definition Unit.h:156
@ MODIFIER_TYPE_FLAT_END
Definition Unit.h:159
@ TOTAL_VALUE
Definition Unit.h:158
@ BASE_PCT_EXCLUDE_CREATE
Definition Unit.h:157
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition Unit.h:152
@ UNIT_MASK_NONE
Definition Unit.h:355
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:364
@ UNIT_MASK_ACCESSORY
Definition Unit.h:365
@ UNIT_MASK_VEHICLE
Definition Unit.h:361
@ UNIT_MASK_GUARDIAN
Definition Unit.h:358
@ UNIT_MASK_MINION
Definition Unit.h:357
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:170
@ MINDAMAGE
Definition Unit.h:171
@ MAXDAMAGE
Definition Unit.h:172
UnitMods
Definition Unit.h:176
@ UNIT_MOD_DAMAGE_OFFHAND
Definition Unit.h:219
@ UNIT_MOD_COMBO_POINTS
Definition Unit.h:187
@ UNIT_MOD_STAT_INTELLECT
Definition Unit.h:180
@ UNIT_MOD_STAT_SPIRIT
Definition Unit.h:181
@ UNIT_MOD_ARMOR
Definition Unit.h:209
@ UNIT_MOD_RESISTANCE_SHADOW
Definition Unit.h:214
@ UNIT_MOD_RESISTANCE_FROST
Definition Unit.h:213
@ UNIT_MOD_END
Definition Unit.h:221
@ UNIT_MOD_ATTACK_POWER
Definition Unit.h:216
@ UNIT_MOD_RESISTANCE_HOLY
Definition Unit.h:210
@ UNIT_MOD_RESISTANCE_START
Definition Unit.h:225
@ UNIT_MOD_SOUL_SHARDS
Definition Unit.h:190
@ UNIT_MOD_RESISTANCE_ARCANE
Definition Unit.h:215
@ UNIT_MOD_ESSENCE
Definition Unit.h:202
@ UNIT_MOD_ARCANE_CHARGES
Definition Unit.h:199
@ UNIT_MOD_ENERGY
Definition Unit.h:186
@ UNIT_MOD_HEALTH
Definition Unit.h:182
@ UNIT_MOD_RUNES
Definition Unit.h:188
@ UNIT_MOD_DAMAGE_RANGED
Definition Unit.h:220
@ UNIT_MOD_HOLY_POWER
Definition Unit.h:192
@ UNIT_MOD_PAIN
Definition Unit.h:201
@ UNIT_MOD_BURNING_EMBERS
Definition Unit.h:197
@ UNIT_MOD_RUNE_UNHOLY
Definition Unit.h:205
@ UNIT_MOD_POWER_START
Definition Unit.h:227
@ UNIT_MOD_RUNE_BLOOD
Definition Unit.h:203
@ UNIT_MOD_CHI
Definition Unit.h:195
@ UNIT_MOD_RESISTANCE_FIRE
Definition Unit.h:211
@ UNIT_MOD_STAT_STRENGTH
Definition Unit.h:177
@ UNIT_MOD_RUNE_FROST
Definition Unit.h:204
@ UNIT_MOD_FURY
Definition Unit.h:200
@ UNIT_MOD_ALTERNATE
Definition Unit.h:193
@ UNIT_MOD_RESISTANCE_NATURE
Definition Unit.h:212
@ UNIT_MOD_ALTERNATE_ENCOUNTER
Definition Unit.h:207
@ UNIT_MOD_LUNAR_POWER
Definition Unit.h:191
@ UNIT_MOD_MAELSTROM
Definition Unit.h:194
@ UNIT_MOD_DEMONIC_FURY
Definition Unit.h:198
@ UNIT_MOD_ALTERNATE_QUEST
Definition Unit.h:206
@ UNIT_MOD_STAT_AGILITY
Definition Unit.h:178
@ UNIT_MOD_ALTERNATE_MOUNT
Definition Unit.h:208
@ UNIT_MOD_INSANITY
Definition Unit.h:196
@ UNIT_MOD_FOCUS
Definition Unit.h:185
@ UNIT_MOD_DAMAGE_MAINHAND
Definition Unit.h:218
@ UNIT_MOD_MANA
Definition Unit.h:183
@ UNIT_MOD_STAT_START
Definition Unit.h:223
@ UNIT_MOD_RAGE
Definition Unit.h:184
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:179
@ UNIT_MOD_RUNIC_POWER
Definition Unit.h:189
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition Unit.h:217
TC_GAME_API float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:111
DeathState
Definition Unit.h:251
@ CORPSE
Definition Unit.h:254
@ DEAD
Definition Unit.h:255
@ ALIVE
Definition Unit.h:252
@ JUST_RESPAWNED
Definition Unit.h:256
@ JUST_DIED
Definition Unit.h:253
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition Unit.h:603
CurrentSpellTypes
Definition Unit.h:596
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:599
@ CURRENT_GENERIC_SPELL
Definition Unit.h:598
@ CURRENT_MELEE_SPELL
Definition Unit.h:597
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:600
UnitState
Definition Unit.h:260
@ UNIT_STATE_DISTRACTED
Definition Unit.h:273
@ UNIT_STATE_DIED
Definition Unit.h:261
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:275
@ UNIT_STATE_POSSESSED
Definition Unit.h:277
@ UNIT_STATE_UNATTACKABLE
Definition Unit.h:299
@ UNIT_STATE_LOST_CONTROL
Definition Unit.h:302
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition Unit.h:303
@ UNIT_STATE_CONFUSED
Definition Unit.h:272
@ UNIT_STATE_ROOT
Definition Unit.h:271
@ UNIT_STATE_CHARGING
Definition Unit.h:278
@ UNIT_STATE_CONTROLLED
Definition Unit.h:301
@ UNIT_STATE_FLEEING
Definition Unit.h:268
@ UNIT_STATE_CANNOT_TURN
Definition Unit.h:305
@ UNIT_STATE_MOVING
Definition Unit.h:300
@ UNIT_STATE_MOVE
Definition Unit.h:281
@ UNIT_STATE_MELEE_ATTACKING
Definition Unit.h:262
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:269
@ UNIT_STATE_FOCUSING
Definition Unit.h:267
@ UNIT_STATE_CASTING
Definition Unit.h:276
@ UNIT_STATE_STUNNED
Definition Unit.h:264
@ UNIT_STATE_CHARMED
Definition Unit.h:263
MeleeHitOutcome
Definition Unit.h:385
@ MELEE_HIT_CRUSHING
Definition Unit.h:387
@ MELEE_HIT_BLOCK
Definition Unit.h:386
@ MELEE_HIT_CRIT
Definition Unit.h:387
@ MELEE_HIT_NORMAL
Definition Unit.h:387
@ MELEE_HIT_EVADE
Definition Unit.h:386
@ MELEE_HIT_DODGE
Definition Unit.h:386
@ MELEE_HIT_MISS
Definition Unit.h:386
@ MELEE_HIT_PARRY
Definition Unit.h:386
@ MELEE_HIT_GLANCING
Definition Unit.h:387
#define MAX_AGGRO_RESET_TIME
Definition Unit.h:44
#define SPELL_DAZED
Definition Unit.h:37
#define ATTACK_DISPLAY_DELAY
Definition Unit.h:631
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:150
#define CURRENT_MAX_SPELL
Definition Unit.h:604
CombatRating
Definition Unit.h:316
@ CR_VERSATILITY_DAMAGE_TAKEN
Definition Unit.h:347
@ CR_ARMOR_PENETRATION
Definition Unit.h:341
@ CR_VERSATILITY_DAMAGE_DONE
Definition Unit.h:345
ReactiveType
Definition Unit.h:612
@ MAX_REACTIVE
Definition Unit.h:615
@ REACTIVE_DEFENSE
Definition Unit.h:613
@ REACTIVE_DEFENSE_2
Definition Unit.h:614
TC_GAME_API float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:98
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition Unit.h:38
UnitModifierPctType
Definition Unit.h:163
@ MODIFIER_TYPE_PCT_END
Definition Unit.h:166
@ TOTAL_PCT
Definition Unit.h:165
@ BASE_PCT
Definition Unit.h:164
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:565
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
Unit * GetTarget() const
Definition SpellAuras.h:81
void SetRemoveMode(AuraRemoveMode mode)
Definition SpellAuras.h:95
uint16 GetSlot() const
Definition SpellAuras.h:84
bool IsPositive() const
Definition SpellAuras.h:88
void _HandleEffect(uint8 effIndex, bool apply)
Aura * GetBase() const
Definition SpellAuras.h:82
uint32 GetEffectMask() const
Definition SpellAuras.h:86
AuraRemoveMode GetRemoveMode() const
Definition SpellAuras.h:96
bool HasEffect(uint8 effect) const
Definition SpellAuras.h:87
void ChangeAmount(SpellEffectValue newAmount, bool mark=true, bool onStackOrReapply=false, AuraEffect const *triggeredBy=nullptr)
SpellInfo const * GetSpellInfo() const
AuraType GetAuraType() const
void HandleEffect(AuraApplication *aurApp, uint8 mode, bool apply, AuraEffect const *triggeredBy=nullptr)
SpellEffectInfo const & GetSpellEffectInfo() const
int32 GetAmountAsInt() const
uint32 GetId() const
bool IsAffectingSpell(SpellInfo const *spell) const
int32 GetMiscValueB() const
Unit * GetCaster() const
int32 GetMiscValue() const
SpellEffectValue const m_baseAmount
Aura * GetBase() const
SpellEffectValue GetAmount() const
ObjectGuid GetCasterGUID() const
bool HasMoreThanOneEffectForType(AuraType auraType) const
virtual void _UnapplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
void CallScriptEffectCalcCritChanceHandlers(AuraEffect const *aurEff, AuraApplication const *aurApp, Unit const *victim, float &critChance)
ObjectGuid GetCastId() const
Definition SpellAuras.h:186
bool IsArea() const
int32 GetMaxDuration() const
Definition SpellAuras.h:217
void CallScriptEffectAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
virtual std::string GetDebugInfo() const
void CallScriptDispel(DispelInfo *dispelInfo)
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
ApplicationMap const & GetApplicationMap()
Definition SpellAuras.h:286
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:196
Trinity::IteratorPair< DBStorageIterator< AuraEffect * > > GetAuraEffects()
Definition SpellAuras.h:362
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
ObjectGuid GetCasterGUID() const
Definition SpellAuras.h:187
bool HasEffect(uint8 effIndex) const
Definition SpellAuras.h:277
bool IsRemoved() const
Definition SpellAuras.h:254
void PrepareProcToTrigger(AuraApplication *aurApp, ProcEventInfo &eventInfo, TimePoint now)
uint32 GetProcEffectMask(AuraApplication *aurApp, ProcEventInfo &eventInfo, TimePoint now) const
WorldObject * GetOwner() const
Definition SpellAuras.h:195
bool ModCharges(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool CanStackWith(Aura const *existingAura) const
uint32 GetId() const
Definition SpellAuras.h:183
int32 CalcDispelChance(Unit const *auraTarget, bool offensive) const
bool IsAppliedOnTarget(ObjectGuid guid) const
void AddProcCooldown(SpellProcEntry const *procEntry, TimePoint now)
int32 GetDuration() const
Definition SpellAuras.h:222
void UpdateOwner(uint32 diff, WorldObject *owner)
void UnregisterSingleTarget()
bool IsDeathPersistent() const
void PrepareProcChargeDrop(SpellProcEntry const *procEntry, ProcEventInfo const &eventInfo)
AuraEffect * GetEffect(uint32 index) const
Unit * GetCaster() const
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)
void TriggerProcOnEvent(uint32 procEffectMask, AuraApplication *aurApp, ProcEventInfo &eventInfo)
void CallScriptEffectAfterAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
void CallScriptEffectManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
AuraObjectType GetType() const
uint8 GetStackAmount() const
Definition SpellAuras.h:238
uint8 GetCharges() const
Definition SpellAuras.h:229
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:182
ObjectGuid GetCastItemGUID() const
Definition SpellAuras.h:188
uint32 GetEffectMask() const
void HandleAuraSpecificMods(AuraApplication const *aurApp, Unit *caster, bool apply, bool onReapply)
Difficulty GetCastDifficulty() const
Definition SpellAuras.h:184
void SetIsSingleTarget(bool val)
Definition SpellAuras.h:258
virtual void _ApplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
bool IsPassive() const
std::unordered_map< ObjectGuid, AuraApplication * > ApplicationMap
Definition SpellAuras.h:172
void CallScriptEffectAfterManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
void CallScriptAfterDispel(DispelInfo *dispelInfo)
void _Remove(AuraRemoveMode removeMode)
bool IsSingleTarget() const
Definition SpellAuras.h:256
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter< T > setter, float percent, bool apply)
Definition BaseEntity.h:320
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter< T > setter, typename UF::UpdateFieldPrivateSetter< T >::value_type value)
Definition BaseEntity.h:221
WowCS::EntityFragmentsHolder m_entityFragments
Definition BaseEntity.h:353
void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter< T > const &)
Definition BaseEntity.h:208
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter, uint32 index)
Definition BaseEntity.h:256
UF::UpdateFieldHolder m_values
Definition BaseEntity.h:205
bool IsInWorld() const
Definition BaseEntity.h:158
CreateObjectBits m_updateFlag
Definition BaseEntity.h:352
virtual void DestroyForPlayer(Player const *target) const
void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter< T > setter, typename UF::UpdateFieldPrivateSetter< T >::value_type flag)
Definition BaseEntity.h:228
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter< T > setter)
Definition BaseEntity.h:263
UF::DynamicUpdateFieldSetter< T >::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter)
Definition BaseEntity.h:242
void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter< T > setter, typename UF::UpdateFieldPrivateSetter< T >::value_type flag)
Definition BaseEntity.h:235
bool IsCreature() const
Definition BaseEntity.h:172
bool IsPlayer() const
Definition BaseEntity.h:173
TypeID m_objectTypeId
Definition BaseEntity.h:351
TypeID GetTypeId() const
Definition BaseEntity.h:166
void SuppressPvPCombat(UnitFilter *unitFilter=nullptr)
void EndAllPvECombat(UnitFilter *unitFilter=nullptr)
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
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:125
virtual void JustSummonedGameobject(GameObject *)
Definition CreatureAI.h:120
virtual void OnSpellClick(Unit *, bool)
Definition CreatureAI.h:230
virtual void SummonedGameobjectDespawn(GameObject *)
Definition CreatureAI.h:121
virtual void OnSpellFailed(SpellInfo const *)
Definition CreatureAI.h:141
virtual void JustUnregisteredAreaTrigger(AreaTrigger *)
Definition CreatureAI.h:129
virtual void KilledUnit(Unit *)
Definition CreatureAI.h:110
virtual void JustRegisteredAreaTrigger(AreaTrigger *)
Definition CreatureAI.h:128
virtual void JustRegisteredDynObject(DynamicObject *)
Definition CreatureAI.h:124
bool IsTreatedAsRaidUnit() const
Definition Creature.h:235
bool isWorldBoss() const
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
void AllLootRemovedFromCorpse()
bool CanHaveLoot() const
Definition Creature.h:295
GuidUnorderedSet const & GetTapList() const
Definition Creature.h:304
void SetTappedBy(Unit const *unit, bool withGroup=true)
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
float GetSpellDamageMod(CreatureClassifications classification) const
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:266
uint32 GetLootId() const
bool CannotPenetrateWater() const
Definition Creature.h:150
bool CanEnterWater() const override
Definition Creature.h:160
void SetDisplayId(uint32 displayId, bool setNative=false) override
void LowerPlayerDamageReq(uint64 unDamage)
bool HasFlag(CreatureStaticFlags flag) const
Definition Creature.h:472
bool IsFullyLooted() const
void SendAIReaction(AiReaction reactionType)
bool IsAquatic() const
Definition Creature.h:136
void CallAssistance()
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)
static bool IsInArea(uint32 objectAreaId, uint32 areaId)
std::set< MountTypeXCapabilityEntry const *, MountTypeXCapabilityEntryComparator > MountTypeXCapabilitySet
Definition DB2Stores.h:441
void ResistDamage(uint32 amount)
Definition Unit.cpp:220
void AbsorbDamage(uint32 amount)
Definition Unit.cpp:212
ProcFlagsHit m_hitMask
Definition Unit.h:435
uint32 m_resist
Definition Unit.h:433
void ModifyDamage(int32 amount)
Definition Unit.cpp:206
Unit * GetVictim() const
Definition Unit.h:447
Unit * GetAttacker() const
Definition Unit.h:446
DamageInfo(Unit *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
Definition Unit.cpp:136
uint32 GetOriginalDamage() const
Definition Unit.h:453
uint32 m_block
Definition Unit.h:434
SpellInfo const * GetSpellInfo() const
Definition Unit.h:448
void BlockDamage(uint32 amount)
Definition Unit.cpp:232
WeaponAttackType GetAttackType() const
Definition Unit.h:451
uint32 GetResist() const
Definition Unit.h:455
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:449
uint32 m_absorb
Definition Unit.h:432
uint32 m_damage
Definition Unit.h:426
ProcFlagsHit GetHitMask() const
Definition Unit.cpp:245
uint32 GetDamage() const
Definition Unit.h:452
uint32 GetAbsorb() const
Definition Unit.h:454
uint8 GetRemovedCharges() const
Definition Unit.h:398
bool RollDispel() const
Definition Unit.cpp:131
int32 _chance
Definition Unit.h:147
DispelableAura(Aura *aura, int32 dispelChance, uint8 dispelCharges)
Definition Unit.cpp:124
uint32 GetSpellId() const
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:212
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition Object.h:213
static void RemoveCreatureFromGroup(CreatureGroup *group, Creature *member)
ObjectGuid GetOwnerGUID() const override
Definition GameObject.h:245
uint32 GetSpellId() const
Definition GameObject.h:252
void SetOwnerGUID(ObjectGuid owner)
Definition GameObject.h:235
void SetRespawnTime(int32 respawn)
Definition Group.h:205
uint32 GetMembersCount() const
Definition Group.h:335
ObjectGuid GetLooterGuid() const
Definition Group.cpp:1668
GroupRefManager & GetMembers()
Definition Group.h:332
bool InitStatsForLevel(uint8 level)
Definition Pet.cpp:839
uint32 _heal
Definition Unit.h:466
Unit * GetHealer() const
Definition Unit.h:480
uint32 _effectiveHeal
Definition Unit.h:468
uint32 GetAbsorb() const
Definition Unit.h:485
uint32 GetEffectiveHeal() const
Definition Unit.h:484
SpellInfo const * GetSpellInfo() const
Definition Unit.h:486
uint32 _absorb
Definition Unit.h:469
uint32 GetHitMask() const
Definition Unit.cpp:265
uint32 GetOriginalHeal() const
Definition Unit.h:483
void SetEffectiveHeal(uint32 amount)
Definition Unit.h:478
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:487
void AbsorbHeal(uint32 amount)
Definition Unit.cpp:255
Unit * GetTarget() const
Definition Unit.h:481
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition Unit.cpp:250
uint32 GetHeal() const
Definition Unit.h:482
uint32 _hitMask
Definition Unit.h:472
Definition Item.h:179
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
bool IsBroken() const
Definition Item.h:267
bool HaveLootFor(uint32 loot_id) const
Definition LootMgr.h:92
void GameObjectRelocation(GameObject *go, float x, float y, float z, float orientation, bool respawnRelocationOnFail=true)
Definition Map.cpp:1082
bool IsDungeon() const
Definition Map.cpp:3267
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition Map.cpp:1050
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:1694
MapDifficultyEntry const * GetMapDifficulty() const
Definition Map.cpp:3252
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f)
Definition Map.cpp:1745
BattlegroundMap * ToBattlegroundMap()
Definition Map.h:493
Difficulty GetDifficultyID() const
Definition Map.h:360
MapEntry const * GetEntry() const
Definition Map.h:231
PlayerList const & GetPlayers() const
Definition Map.h:403
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition Map.cpp:1023
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:3542
Transport * GetTransport(ObjectGuid const &guid)
Definition Map.cpp:3562
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, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
MovementGeneratorType GetCurrentMovementGeneratorType() const
void PropagateSpeedChange()
void MoveFleeing(Unit *enemy, Milliseconds time=0ms, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveTargetedHome()
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveKnockbackFrom(Position const &origin, float speedXY, float speedZ, float angle=M_PI, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void SetFacing(float angle)
LowType GetCounter() const
Definition ObjectGuid.h:336
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
bool IsMOTransport() const
Definition ObjectGuid.h:376
bool IsPlayer() const
Definition ObjectGuid.h:369
std::string ToString() const
static CreatureModel const * ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=nullptr)
void SetDynamicFlag(uint32 flag)
Definition Object.h:97
float GetObjectScale() const
Definition Object.h:92
Player * ToPlayer()
Definition Object.h:126
bool HasDynamicFlag(uint32 flag) const
Definition Object.h:96
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData *data, UF::UpdateFieldFlag flags, Player const *target) const
Definition Object.cpp:100
uint32 GetEntry() const
Definition Object.h:89
Creature * ToCreature()
Definition Object.h:121
virtual void ClearValuesChangesMask()
Definition Object.cpp:130
virtual void SetObjectScale(float scale)
Definition Object.h:93
Unit * ToUnit()
Definition Object.h:116
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:1835
std::string GetDebugInfo() const override
Definition Pet.cpp:1944
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:1603
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
void StopCastingBindSight() const
Definition Player.cpp:26913
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:26500
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2149
void SendAttackSwingCancelAttack() const
Definition Player.cpp:21841
void AddPetToUpdateFields(PetStable::PetInfo const &pet, PetSaveMode slot, PetStableFlags flags)
Definition Player.cpp:29645
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2804
void DuelComplete(DuelCompleteType type)
Definition Player.cpp:7793
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:6010
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3062
void SendAutoRepeatCancel(Unit *target)
Definition Player.cpp:21854
PetStable & GetOrInitPetStable()
Definition Player.cpp:29637
float GetRatingBonusValue(CombatRating cr) const
Definition Player.cpp:5240
void CharmSpellInitialize()
Definition Player.cpp:22583
void UpdatePvPState(bool onlyFFA=false)
Definition Player.cpp:24066
bool InBattleground() const
Definition Player.h:2584
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4665
void PetSpellInitialize()
Definition Player.cpp:22471
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat.
Definition Player.h:2236
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:27493
bool HaveAtClient(BaseEntity const *u) const
Definition Player.cpp:24475
void SendRemoveControlBar() const
Definition Player.cpp:22623
WorldSession * GetSession() const
Definition Player.h:2272
OutdoorPvP * GetOutdoorPvP() const
Definition Player.cpp:26206
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:8667
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:2070
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
void StopCastingCharm()
Definition Player.cpp:22269
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:1226
Battleground * GetBattleground() const
Definition Player.cpp:25719
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition Player.cpp:5301
bool IsGameMaster() const
Definition Player.h:1309
std::array< uint8, MAX_MOVE_TYPE > m_forced_speed_changes
Definition Player.h:2719
void PossessSpellInitialize()
Definition Player.cpp:22510
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9669
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2796
std::unique_ptr< DuelInfo > duel
Definition Player.h:2143
uint8 GetSubGroup() const
Definition Player.h:2802
void VehicleSpellInitialize()
Definition Player.cpp:22536
Team GetEffectiveTeam() const
Definition Player.h:2427
void SetFactionForRace(uint8 race)
Definition Player.cpp:6497
Stats GetPrimaryStat() const
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:21986
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:28000
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:24109
bool IsInSameGroupWith(Player const *p) const
Definition Player.cpp:2142
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:270
DamageInfo * _damageInfo
Definition Unit.h:525
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:292
HealInfo * _healInfo
Definition Unit.h:526
Spell const * GetProcSpell() const
Definition Unit.h:514
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:281
Spell * _spell
Definition Unit.h:524
Mechanics Mechanic
Definition SpellInfo.h:226
AuraType ApplyAuraName
Definition SpellInfo.h:216
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
SpellEffectName Effect
Definition SpellInfo.h:215
float BonusCoefficientFromAP
Definition SpellInfo.h:236
float BonusCoefficient
Definition SpellInfo.h:223
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition SpellInfo.h:238
SpellEffIndex EffectIndex
Definition SpellInfo.h:214
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void ResetCooldowns(Predicate &&predicate, bool update=false)
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false, Optional< Duration > forcedCooldown={})
DiminishingLevels GetDiminishingReturnsMaxLevel() const
Mechanics GetEffectMechanic(SpellEffIndex effIndex) const
SpellInfo const * GetFirstRankSpell() const
bool HasEffect(SpellEffectName effect) const
std::unordered_set< uint32 > Labels
Definition SpellInfo.h:421
uint64 GetAllEffectsMechanicMask() const
bool IsRequiringDeadTarget() const
uint32 const Id
Definition SpellInfo.h:328
EnumFlag< SpellAuraInterruptFlags2 > AuraInterruptFlags2
Definition SpellInfo.h:378
bool IsGroupBuff() const
bool IsDeathPersistent() const
bool IsCooldownStartedOnEvent() const
bool IsPassive() const
uint32 Mechanic
Definition SpellInfo.h:332
bool HasAnyAuraInterruptFlag() const
bool IsStackableOnOneSlotWithDifferentCasters() const
uint32 GetDispelMask() const
SpellSpecificType GetSpellSpecific() const
DiminishingReturnsType GetDiminishingReturnsGroupType() const
uint32 Dispel
Definition SpellInfo.h:331
bool IsMultiSlotAura() const
int32 GetMaxDuration() const
int32 GetDiminishingReturnsLimitDuration() const
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
uint32 SchoolMask
Definition SpellInfo.h:419
uint32 CasterAuraState
Definition SpellInfo.h:358
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
bool IsItemFitToSpellRequirements(Item const *item) const
flag128 SpellFamilyFlags
Definition SpellInfo.h:415
WeaponAttackType GetAttackType() const
SpellSchoolMask GetSchoolMask() const
AuraStateType GetAuraState() const
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:456
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
uint32 Attributes
Definition SpellInfo.h:333
bool IsPassiveStackableWithRanks() const
uint32 MaxAffectedTargets
Definition SpellInfo.h:413
int32 GetDuration() const
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:587
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
bool CanPierceImmuneAura(SpellInfo const *auraSpellInfo) const
std::bitset< MAX_SPELL_EFFECTS > NegativeEffects
Definition SpellInfo.h:351
bool IsPositive() const
uint32 DmgClass
Definition SpellInfo.h:416
bool IsRangedWeaponSpell() const
EnumFlag< SpellAuraInterruptFlags > AuraInterruptFlags
Definition SpellInfo.h:377
bool HasAura(AuraType aura) const
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const
Definition SpellInfo.h:478
bool HasLabel(uint32 labelId) const
uint32 CategoryId
Definition SpellInfo.h:330
uint32 SpellFamilyName
Definition SpellInfo.h:414
bool IsPositiveEffect(uint8 effIndex) const
bool IsSingleTarget() const
static CreatureImmunities const * GetCreatureImmunities(int32 creatureImmunitiesId)
Definition SpellMgr.cpp:687
Definition Spell.h:277
SpellState getState() const
Definition Spell.h:550
SpellInfo const * GetSpellInfo() const
Definition Spell.h:702
void CallScriptCalcDamageHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition Spell.cpp:9031
bool IsInterruptable() const
Definition Spell.h:683
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition Spell.cpp:5791
bool IsProcDisabled() const
Definition Spell.cpp:8364
int32 GetCastTime() const
Definition Spell.h:659
std::string GetDebugInfo() const
Definition Spell.cpp:9306
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:4699
int32 GetProcChainLength() const
Definition Spell.h:679
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:9094
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:8221
void cancel()
Definition Spell.cpp:3600
void SendChannelUpdate(uint32 time, Optional< SpellCastResult > result={})
Definition Spell.cpp:5254
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3419
void CallScriptCalcHealingHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition Spell.cpp:9043
Spell ** m_selfContainer
Definition Spell.h:714
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:682
UsedSpellMods m_appliedMods
Definition Spell.h:654
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition Spell.cpp:9019
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition Spell.cpp:4342
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
Position GetPositionWithOffset(Position const &offset) 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.
constexpr end_iterator end() const
constexpr iterator begin() const
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
virtual void OnCharmed(bool isNew)
Definition UnitAI.cpp:49
Definition Unit.h:635
float GetUnitMissChance() const
Definition Unit.cpp:2838
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition Unit.cpp:12749
void SetCannotTurn(bool apply)
Definition Unit.cpp:8572
bool SetCanDoubleJump(bool enable)
Definition Unit.cpp:13908
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:820
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition Unit.cpp:9664
Unit * GetCharmed() const
Definition Unit.h:1212
void ClearUnitState(uint32 f)
Definition Unit.h:744
void OutDebugInfo() const
Definition Unit.cpp:13150
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition Unit.cpp:686
void RemoveAreaTrigger(uint32 spellId)
Definition Unit.cpp:5485
bool IsStopped() const
Definition Unit.h:1727
void SetFlightCapabilityID(int32 flightCapabilityId, bool clientUpdate)
Definition Unit.cpp:9003
bool IsVehicle() const
Definition Unit.h:754
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
Definition Unit.cpp:8242
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:6247
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition Unit.h:647
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8697
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:1186
bool IsWithinMeleeRange(Unit const *obj) const
Definition Unit.h:710
void ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction={}, ObjectGuid transportGuid=ObjectGuid::Empty)
Definition Unit.cpp:14049
void SetImmuneToAll(bool apply, bool keepCombat)
Definition Unit.cpp:8505
bool IsCharmed() const
Definition Unit.h:1236
void SetImmuneToPC(bool apply, bool keepCombat)
Definition Unit.cpp:8518
bool m_duringRemoveFromWorld
Definition Unit.h:2034
float GetBoundingRadius() const
Definition Unit.h:707
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:6811
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3751
Vehicle * GetVehicle() const
Definition Unit.h:1784
EnumFlag< SpellAuraInterruptFlags2 > m_interruptMask2
Definition Unit.h:1935
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition Unit.cpp:707
void SetVisible(bool x)
Definition Unit.cpp:8768
virtual bool IsMovementPreventedByCasting() const
Definition Unit.cpp:3261
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3955
int32 SpellAbsorbBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 absorbamount) const
Definition Unit.cpp:7708
bool SetAlwaysAllowPitching(bool enable)
Definition Unit.cpp:13811
virtual void UpdateResistances(uint32 school)
Definition Unit.cpp:9891
bool SetStrafingDisabled(bool disable)
Definition Unit.cpp:13687
void DeleteCharmInfo()
Definition Unit.cpp:10387
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5378
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition Unit.cpp:8585
bool IsHunterPet() const
Definition Unit.h:752
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1342
uint32 GetSchoolImmunityMask() const
Definition Unit.cpp:7815
std::unique_ptr< SpellHistory > _spellHistory
Definition Unit.h:2044
void UpdateAttackTimeField(WeaponAttackType att)
Definition Unit.cpp:10945
float GetHealthPct() const
Definition Unit.h:796
float m_baseSpellCritChance
Definition Unit.h:1517
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition Unit.h:1589
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition Unit.cpp:6012
int32 MeleeDamageBonusTaken(Unit *attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:8133
bool HasExtraUnitMovementFlag(uint32 f) const
Definition Unit.h:1740
void AIUpdateTick(uint32 diff)
Definition Unit.cpp:10155
virtual void RecalculateObjectScale()
Definition Unit.cpp:10771
void SetHealth(uint64 val)
Definition Unit.cpp:9973
Unit * m_unitMovedByMe
Definition Unit.h:1948
virtual MovementGeneratorType GetDefaultMovementType() const
Definition Unit.cpp:10675
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
Definition Unit.cpp:761
AuraList m_removedAuras
Definition Unit.h:1926
void SetFacingToPoint(Position const &point, bool force=true)
Definition Unit.cpp:13324
bool SetCanAdvFly(bool enable)
Definition Unit.cpp:13970
uint32 GetUnitMovementFlags() const
Definition Unit.h:1735
LiquidTypeEntry const * _lastLiquid
Definition Unit.h:1964
float GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5089
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7310
void _UpdateAutoRepeatSpell()
Definition Unit.cpp:3021
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition Unit.cpp:14374
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition Unit.cpp:12480
float GetTotalAuraModValue(UnitMods unitMod) const
Definition Unit.cpp:9837
float GetMaxPositiveAuraModifier(AuraType auraType) const
Definition Unit.cpp:5079
AreaTriggerList m_areaTrigger
Definition Unit.h:1917
uint64 CountPctFromMaxHealth(float pct) const
Definition Unit.h:797
bool IsInteractionAllowedInCombat() const
Definition Unit.h:1067
void RestoreDisabledAI()
Definition Unit.cpp:10209
void Heartbeat() override
Definition Unit.cpp:502
int32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype) const
Definition Unit.cpp:7495
void RemoveAllControlled()
Definition Unit.cpp:6613
Pet * ToPet()
Definition Unit.h:1822
ObjectGuid GetDemonCreatorGUID() const
Definition Unit.h:1203
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1030
void RemoveAurasByShapeShift()
Definition Unit.cpp:4334
float GetTotalStatValue(Stats stat) const
Definition Unit.cpp:9821
void SetPlayHoverAnim(bool enable, bool sendUpdate=true)
Definition Unit.cpp:14175
std::unique_ptr< MotionMaster > i_motionMaster
Definition Unit.h:1955
void SetUnitFlag3(UnitFlags3 flags)
Definition Unit.h:856
void SetGender(Gender gender)
Definition Unit.h:768
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition Unit.cpp:2911
bool IsContestedGuard() const
Definition Unit.cpp:12233
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition Unit.h:2030
void UpdateUnitMod(UnitMods unitMod)
Definition Unit.cpp:9675
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition Unit.cpp:9774
float GetSpeed(UnitMoveType mtype) const
Definition Unit.cpp:8932
bool SetFall(bool enable)
Definition Unit.cpp:13424
void _UnregisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5297
bool m_canModifyStats
Definition Unit.h:1940
float GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5169
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3828
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12467
int64 ModifyHealth(int64 val)
Definition Unit.cpp:8599
std::array< uint32, MAX_REACTIVE > m_reactiveTimer
Definition Unit.h:1957
void AddExtraUnitMovementFlag(uint32 f)
Definition Unit.h:1738
std::shared_ptr< UnitAI > i_AI
Definition Unit.h:2024
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition Unit.cpp:14509
void SetCurrentCastSpell(Spell *pSpell)
Definition Unit.cpp:3081
bool _isCombatDisallowed
Definition Unit.h:2049
void SetFullHealth()
Definition Unit.h:802
void TriggerOnHealthChangeAuras(uint64 oldVal, uint64 newVal)
Definition Unit.cpp:8666
void SetMinionGUID(ObjectGuid guid)
Definition Unit.h:1196
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo) const
Definition Unit.cpp:6902
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition Unit.cpp:10803
Diminishing m_Diminishing
Definition Unit.h:2012
void SetHoverHeight(float hoverHeight)
Definition Unit.h:1147
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10731
void FinishSpell(CurrentSpellTypes spellType, SpellCastResult result=SPELL_CAST_OK)
Definition Unit.cpp:3189
void EnergizeBySpell(Unit *victim, SpellInfo const *spellInfo, int32 damage, Powers powerType)
Definition Unit.cpp:6798
void SetInitialPowerValue(Powers powerType)
Definition Unit.cpp:5750
void SendPlaySpellVisual(Unit *target, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime=false, float launchDelay=0.0f)
Definition Unit.cpp:12305
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition Unit.cpp:13091
std::array< Spell *, CURRENT_MAX_SPELL > m_currentSpells
Definition Unit.h:1922
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition Unit.cpp:3715
virtual void OnPhaseChange()
Definition Unit.cpp:12463
void SetConfused(bool apply)
Definition Unit.cpp:11748
void _UpdateSpells(uint32 time)
Definition Unit.cpp:2959
ThreatManager & GetThreatManager()
Definition Unit.h:1078
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition Unit.h:883
void AddToWorld() override
Definition Unit.cpp:10233
virtual float GetArmorMultiplierForTarget(WorldObject const *) const
Definition Unit.h:809
void RestoreFaction()
Definition Unit.cpp:12048
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition Unit.cpp:8270
virtual void AtExitCombat()
Definition Unit.cpp:9240
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition Unit.cpp:3602
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4827
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1060
float GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5189
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:14332
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition Unit.cpp:10670
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition Unit.cpp:4573
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11545
uint8 GetClass() const
Definition Unit.h:764
float GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5199
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9853
void SetStunned(bool apply)
Definition Unit.cpp:11642
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition Unit.h:1501
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9873
uint32 m_state
Definition Unit.h:2010
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition Unit.cpp:12636
bool CanUseAttackType(uint8 attacktype) const
Definition Unit.cpp:2607
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:670
Player * GetDemonCreatorPlayer() const
Definition Unit.cpp:6197
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5455
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition Unit.cpp:4819
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition Unit.cpp:3246
uint32 GetMountDisplayId() const
Definition Unit.h:913
void UpdateAllDamageDoneMods()
Definition Unit.cpp:9768
Vehicle * m_vehicle
Definition Unit.h:1960
void RemoveVisibleAura(AuraApplication *aurApp)
Definition Unit.cpp:724
Totem * ToTotem()
Definition Unit.h:1825
int64 GetHealthGain(int64 dVal)
Definition Unit.cpp:8641
Creature * GetVehicleCreatureBase() const
Definition Unit.cpp:12132
std::unique_ptr< CharmInfo > m_charmInfo
Definition Unit.h:1952
void UpdateDisplayPower()
Definition Unit.cpp:5808
float GetCollisionHeight() const override
Definition Unit.cpp:14533
void AddExtraUnitMovementFlag2(uint32 f)
Definition Unit.h:1744
void RemoveAllGameObjects()
Definition Unit.cpp:5442
static void DealHeal(HealInfo &healInfo)
Definition Unit.cpp:6524
bool isPossessedByPlayer() const
Definition Unit.cpp:6640
void SendClearTarget()
Definition Unit.cpp:13192
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:645
void _RegisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5290
void UpdateSpeed(UnitMoveType mtype)
Definition Unit.cpp:8778
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:799
bool IsPolymorphed() const
Definition Unit.cpp:10758
void CancelTravelShapeshiftForm(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition Unit.h:1507
bool IsAreaSpiritHealer() const
Definition Unit.h:1017
void PlayOneShotAnimKitId(uint16 animKitId)
Definition Unit.cpp:11160
float m_weaponDamage[MAX_ATTACK][2]
Definition Unit.h:1939
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1504
void SetFaction(uint32 faction) override
Definition Unit.h:872
virtual void SetPvP(bool state)
Definition Unit.cpp:12241
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1191
uint64 GetMechanicImmunityMask() const
Definition Unit.cpp:7835
void CancelShapeshiftForm(bool onlyTravelShapeshiftForm=false, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition Unit.cpp:9500
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition Unit.cpp:10903
SpellEffectValue GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition Unit.cpp:14250
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3305
float GetCombatRatingReduction(CombatRating cr) const
Definition Unit.cpp:12521
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition Unit.cpp:4007
void RemoveExtraUnitMovementFlag(uint32 f)
Definition Unit.h:1739
bool SetEnableFullSpeedTurning(bool enable)
Definition Unit.cpp:13749
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition Unit.cpp:2107
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:14337
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:1193
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK) const =0
Unit * GetVehicleRoot() const
Definition Unit.cpp:12116
void SetCantProc(bool apply)
Definition Unit.cpp:11023
Unit * GetCharmer() const
Definition Unit.h:1209
void SetSpeed(UnitMoveType mtype, float newValue)
Definition Unit.cpp:8937
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, Aura *except=nullptr) const
Definition Unit.cpp:3812
void ExitAllAreaTriggers()
Definition Unit.cpp:5533
int32 m_procChainLength
Definition Unit.h:1908
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition Unit.cpp:9644
Unit * getAttackerForHelper() const
Definition Unit.cpp:5830
std::forward_list< AuraEffect * > AuraEffectList
Definition Unit.h:652
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2798
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:10046
void TriggerOnPowerChangeAuras(Powers power, int32 oldVal, int32 newVal)
Definition Unit.cpp:10108
void SendMeleeAttackStart(Unit *victim)
Definition Unit.cpp:2551
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition Unit.cpp:11072
void UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
Definition Unit.cpp:9025
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition Unit.h:1961
bool IsInDisallowedMountForm() const
Definition Unit.cpp:9538
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition Unit.cpp:9611
std::vector< AreaTrigger * > AreaTriggerList
Definition Unit.h:1916
VisibleAuraContainer m_visibleAuras
Definition Unit.h:1942
UnitPVPStateFlags GetPvpFlags() const
Definition Unit.h:879
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition Unit.cpp:9738
void _removeAttacker(Unit *pAttacker)
Definition Unit.cpp:5825
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition Unit.cpp:5649
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4718
std::forward_list< AuraApplication * > AuraApplicationList
Definition Unit.h:654
uint32 GetTransformSpell() const
Definition Unit.h:1617
void EnterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5523
void RemoveAllAurasExceptType(AuraType type)
Definition Unit.cpp:4517
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1303
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
Definition Unit.cpp:2499
uint32 _lastExtraAttackSpell
Definition Unit.h:2029
float GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5159
void SetAnimTier(AnimTier animTier, bool notifyClient=true)
Definition Unit.cpp:10745
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition Unit.cpp:1876
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3231
virtual bool CanFly() const =0
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition Unit.cpp:12296
Unit * GetVehicleBase() const
Definition Unit.cpp:12111
bool haveOffhandWeapon() const
Definition Unit.cpp:525
MotionMaster * GetMotionMaster()
Definition Unit.h:1723
bool SetFeatherFall(bool enable)
Definition Unit.cpp:13539
bool IsPet() const
Definition Unit.h:751
Powers GetPowerType() const
Definition Unit.h:811
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:845
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition Unit.cpp:1684
void _addAttacker(Unit *pAttacker)
Definition Unit.cpp:5820
bool SetEnableFullSpeedPitching(bool enable)
Definition Unit.cpp:13780
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsHit hitMask, WeaponAttackType attType)
Definition Unit.cpp:10481
bool _instantCast
Definition Unit.h:2035
void Dismount()
Definition Unit.cpp:8317
std::array< ObjectGuid, MAX_GAMEOBJECT_SLOT > m_ObjectSlot
Definition Unit.h:1502
void SetCharm(Unit *target, bool apply)
Definition Unit.cpp:6443
void SetMovedUnit(Unit *target)
Definition Unit.cpp:10396
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1211
void ClearWorldEffects()
Definition Unit.cpp:14571
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:860
bool SetHover(bool enable, bool updateAnimTier=true)
Definition Unit.cpp:13577
bool CanDualWield() const
Definition Unit.h:703
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3201
void UpdateInterruptMask()
Definition Unit.cpp:741
void StartReactiveTimer(ReactiveType reactive)
Definition Unit.h:1765
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition Unit.cpp:9336
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:10328
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition Unit.cpp:13307
void AddChannelObject(ObjectGuid guid)
Definition Unit.cpp:3059
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition Unit.cpp:10707
float GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5119
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:12249
bool HasInterruptFlag(SpellAuraInterruptFlags flags) const
Definition Unit.h:1599
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4604
bool isAttackingPlayer() const
Definition Unit.cpp:6048
void AtEndOfEncounter(EncounterType type)
Definition Unit.cpp:568
virtual void AtEnterCombat()
Definition Unit.cpp:9216
UnitAIStack i_AIs
Definition Unit.h:2023
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition Unit.cpp:10934
std::unique_ptr< MovementForces > _movementForces
Definition Unit.h:2046
void UpdateSplineMovement(uint32 t_diff)
Definition Unit.cpp:595
uint32 GetDamageReduction(uint32 damage) const
Definition Unit.h:968
std::array< float, MAX_STATS > m_floatStatPosBuff
Definition Unit.h:1899
void SetUnitFlag2(UnitFlags2 flags)
Definition Unit.h:851
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:850
bool CanFreeMove() const
Definition Unit.cpp:9950
std::string GetDebugInfo() const override
Definition Unit.cpp:14591
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition Unit.h:642
virtual bool IsLoading() const
Definition Unit.h:1819
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition Unit.cpp:6135
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3300
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition Unit.h:1937
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition Unit.cpp:8541
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10695
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1246
bool IsSplineEnabled() const
Definition Unit.cpp:14211
std::array< uint32, MAX_ATTACK > m_baseAttackSpeed
Definition Unit.h:1519
void RemoveAllAurasRequiringDeadTarget()
Definition Unit.cpp:4496
void UpdateAuraForGroup()
Definition Unit.cpp:11008
Vignettes::VignetteData const * GetVignette() const
Definition Unit.h:1876
void UpdateReactives(uint32 p_time)
Definition Unit.cpp:10869
bool IsAlive() const
Definition Unit.h:1185
virtual bool CanApplyResilience() const
Definition Unit.cpp:12390
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4916
float m_modRangedHitChance
Definition Unit.h:1515
float GetCombatReach() const override
Definition Unit.h:705
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition Unit.cpp:9256
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition Unit.cpp:1775
DeathState m_deathState
Definition Unit.h:1905
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition Unit.cpp:10966
void SetBonusResistanceMod(SpellSchools school, int32 val)
Definition Unit.h:785
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10037
uint32 m_unitTypeMask
Definition Unit.h:1963
void StopMoving()
Definition Unit.cpp:10680
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition Unit.h:646
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6776
void AddPlayerToVision(Player *player)
Definition Unit.cpp:6710
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:998
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6757
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5341
int32 GetFlightCapabilityID() const
Definition Unit.h:1711
virtual ~Unit()
Definition Unit.cpp:392
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12854
uint32 m_removedAurasCount
Definition Unit.h:1928
void RemoveAllAurasOnDeath()
Definition Unit.cpp:4473
uint32 m_movementCounter
Incrementing counter used in movement packets.
Definition Unit.h:2006
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5540
bool IsStandState() const
Definition Unit.cpp:10725
TempSummon * ToTempSummon()
Definition Unit.h:1828
bool IsGravityDisabled() const
Definition Unit.h:1149
CharmInfo * GetCharmInfo()
Definition Unit.h:1242
void AtStartOfEncounter(EncounterType type)
Definition Unit.cpp:543
bool SetCanTransitionBetweenSwimAndFly(bool enable)
Definition Unit.cpp:13842
bool SetDisableInertia(bool disable)
Definition Unit.cpp:13939
ControlList m_Controlled
Definition Unit.h:1232
bool IsInCombatWith(Unit const *who) const
Definition Unit.h:1059
void DisableSpline()
Definition Unit.cpp:659
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1216
void RemoveUnitFlag3(UnitFlags3 flags)
Definition Unit.h:857
AuraMap::iterator m_auraUpdateIterator
Definition Unit.h:1927
UnitAI * GetAI() const
Definition Unit.h:668
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6582
ObjectGuid _lastDamagedTargetGuid
Definition Unit.h:2031
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7121
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13361
void CancelSpellMissiles(uint32 spellId, bool reverseMissile=false, bool abortSpell=false)
Definition Unit.cpp:12360
void FollowerRemoved(AbstractFollower *f)
Definition Unit.cpp:9150
void RemoveAurasWithAttribute(uint32 flags)
Definition Unit.cpp:4147
void RemoveAllFollowers()
Definition Unit.cpp:9155
virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed)
Definition Unit.cpp:9292
void UpdateMountCapability()
Definition Unit.cpp:8459
void FollowerAdded(AbstractFollower *f)
Definition Unit.cpp:9145
void _DeleteRemovedAuras()
Definition Unit.cpp:2948
Player * GetPlayerMovingMe() const
Definition Unit.h:1253
void CancelMountAura(bool force=false)
Definition Unit.cpp:8350
void _ApplyAura(AuraApplication *aurApp, uint32 effMask)
Definition Unit.cpp:3545
void SetUninteractible(bool apply)
Definition Unit.cpp:8564
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition Unit.cpp:6658
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition Unit.cpp:10939
virtual bool HasSpell(uint32) const
Definition Unit.h:1084
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:686
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition Unit.h:650
void AddUnitState(uint32 f)
Definition Unit.h:742
float GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition Unit.cpp:5109
static void ApplyResilience(Unit const *victim, int32 *damage)
Definition Unit.cpp:12395
float GetTotalAuraMultiplier(AuraType auraType) const
Definition Unit.cpp:5074
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition Unit.cpp:8284
AreaTriggerList m_insideAreaTriggers
Definition Unit.h:1918
void SetSheath(SheathState sheathed)
Definition Unit.cpp:5813
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:12106
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition Unit.cpp:5630
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3310
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1217
Gender GetGender() const
Definition Unit.h:767
int32 GetMinPower(Powers power) const
Definition Unit.h:818
virtual void SetInteractionAllowedInCombat(bool interactionAllowed)
Definition Unit.cpp:9302
Unit * EnsureVictim() const
Definition Unit.h:728
uint32 getAttackTimer(WeaponAttackType type) const
Definition Unit.h:700
void RefreshAI()
Definition Unit.cpp:10187
bool IsDuringRemoveFromWorld() const
Definition Unit.h:1820
bool m_ControlledByPlayer
Definition Unit.h:1896
void SetFeared(bool apply)
Definition Unit.cpp:11712
Unit * GetCharmerOrOwner() const
Definition Unit.h:1221
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition Unit.cpp:4928
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition Unit.cpp:4113
virtual void UpdateDamagePhysical(WeaponAttackType attType)
void ExitAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5528
bool IsPlayingHoverAnim() const
Definition Unit.h:1144
void _ApplyAllAuraStatMods()
Definition Unit.cpp:4598
bool SetMoveCantSwim(bool cantSwim)
Definition Unit.cpp:14001
void SetBattlePetCompanionNameTimestamp(uint32 timestamp)
Definition Unit.h:1267
uint32 GetCreatureType() const
Definition Unit.cpp:9451
int32 RewardRage(uint32 baseRage)
Definition Unit.cpp:13099
void AddGameObject(GameObject *gameObj)
Definition Unit.cpp:5357
void InterruptMovementBasedAuras()
Definition Unit.cpp:649
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7917
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4863
bool IsThreatened() const
Definition Unit.cpp:8580
bool SetJumpingDisabled(bool disable)
Definition Unit.cpp:13718
void SendSetVehicleRecId(uint32 vehicleId)
Definition Unit.cpp:14032
bool SetSwim(bool enable)
Definition Unit.cpp:13440
void SetEmoteState(Emote emote)
Definition Unit.h:865
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition Unit.cpp:13027
DynObjectList m_dynObj
Definition Unit.h:1911
PositionUpdateInfo _positionUpdateInfo
Definition Unit.h:2047
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:881
virtual void UpdateNearbyPlayersInteractions()
Definition Unit.cpp:9313
AuraApplicationList m_interruptableAuras
Definition Unit.h:1932
void SetResistance(SpellSchools school, int32 val)
Definition Unit.h:784
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5139
uint32 GetDisplayId() const
Definition Unit.h:1610
void SendCancelSpellVisualKit(uint32 id)
Definition Unit.cpp:12352
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:14358
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1833
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, SpellEffectValue effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications=false)
Definition Unit.cpp:14283
void SendSpellDamageImmune(Unit *target, uint32 spellId, bool isPeriodic)
Definition Unit.cpp:5639
void ModifyAuraState(AuraStateType flag, bool apply)
Definition Unit.cpp:6079
bool IsAIEnabled() const
Definition Unit.h:666
Unit * GetUnitBeingMoved() const
Definition Unit.h:1251
EnumFlag< SpellOtherImmunity > GetSpellOtherImmunityMask() const
Definition Unit.cpp:7845
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4788
UnitAI * GetTopAI() const
Definition Unit.h:674
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition Unit.cpp:2363
bool isPossessing() const
Definition Unit.cpp:6650
uint32 GetNativeDisplayId() const
Definition Unit.h:1613
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7175
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition Unit.cpp:4559
virtual void UpdateArmor()=0
void SetChannelObject(uint32 slot, ObjectGuid guid)
Definition Unit.cpp:3064
uint64 GetMaxHealth() const
Definition Unit.h:789
void UpdateCharmAI()
Definition Unit.cpp:10335
void ClearAllReactives()
Definition Unit.cpp:10858
void ApplyControlStatesIfNeeded()
Definition Unit.cpp:11626
void SetRooted(bool apply)
Definition Unit.cpp:11673
void AddUnitMovementFlag(uint32 f)
Definition Unit.h:1732
ThreatManager m_threatManager
Definition Unit.h:2018
uint32 _oldFactionId
faction before charm
Definition Unit.h:2037
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5853
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition Unit.cpp:12417
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const
Definition Unit.cpp:9942
bool IsHovering() const
Definition Unit.h:1151
std::forward_list< Aura * > AuraList
Definition Unit.h:653
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5179
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4774
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4700
bool PopAI()
Definition Unit.cpp:10176
ObjectGuid GetMinionGUID() const
Definition Unit.h:1195
bool SetCanFly(bool enable)
Definition Unit.cpp:13459
virtual float GetDamageMultiplierForTarget(WorldObject const *) const
Definition Unit.h:808
bool SetCollision(bool disable)
Definition Unit.cpp:13650
bool isPossessed() const
Definition Unit.h:1237
uint16 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition Unit.h:932
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1734
Unit * m_charmed
Definition Unit.h:1951
virtual void UpdateMaxPower(Powers power)=0
uint64 GetHealth() const
Definition Unit.h:788
void _AddAura(UnitAura *aura, Unit *caster)
Definition Unit.cpp:3450
AttackerSet m_attackers
Definition Unit.h:1902
bool IsSummon() const
Definition Unit.h:749
bool IsInWater() const
Definition Unit.cpp:3331
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition Unit.cpp:12151
uint32 GetFaction() const override
Definition Unit.h:871
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition Unit.cpp:14342
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5320
void SendCancelSpellVisual(uint32 id)
Definition Unit.cpp:12334
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, int32 overEnergize, Powers powerType)
Definition Unit.cpp:6785
Unit * m_attacking
Definition Unit.h:1903
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:6146
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4736
AttackerSet const & getAttackers() const
Definition Unit.h:724
void RemoveUnitFlag2(UnitFlags2 flags)
Definition Unit.h:852
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:882
void SetAI(UnitAI *newAI)
Definition Unit.cpp:10170
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4618
void SendTeleportPacket(TeleportLocation const &teleportLocation)
Definition Unit.cpp:12976
float GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition Unit.cpp:2584
bool SetCanTurnWhileFalling(bool enable)
Definition Unit.cpp:13876
std::multimap< uint32, Aura * > AuraMap
Definition Unit.h:641
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5069
void SendPetTalk(uint32 pettalk)
Definition Unit.cpp:10644
bool IsVisible() const
Definition Unit.cpp:8763
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4814
std::unique_ptr< Vignettes::VignetteData > m_vignette
Definition Unit.h:1966
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3914
bool isMoving() const
Definition Unit.h:1804
bool SetWalk(bool enable)
Definition Unit.cpp:13343
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2845
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster) const
Definition Unit.cpp:4896
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8494
void UpdateCreatureType()
Definition Unit.cpp:9475
void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
Definition Unit.h:1601
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition Unit.cpp:1327
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition Unit.cpp:2623
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition Unit.h:698
virtual bool UpdateStats(Stats stat)=0
bool IsImmunedToSpell(SpellInfo const *spellInfo, uint32 effectMask, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7723
void RemoveAllDynObjects()
Definition Unit.cpp:5335
void ClearValuesChangesMask() override
Definition Unit.cpp:14244
bool HasNpcFlag(NPCFlags flags) const
Definition Unit.h:996
void GetAllMinionsByEntry(std::list< TempSummon * > &Minions, uint32 entry)
Definition Unit.cpp:6420
uint32 GetArmor() const
Definition Unit.h:774
float m_modMeleeHitChance
Definition Unit.h:1514
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition Unit.h:1536
void RemoveArenaAuras()
Definition Unit.cpp:4429
void _RemoveAllAuraStatMods()
Definition Unit.cpp:4592
ObjectGuid GetCritterGUID() const
Definition Unit.h:1199
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition Unit.cpp:3990
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:759
void SetFullPower(Powers power)
Definition Unit.h:825
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4241
void SetMovementAnimKitId(uint16 animKitId)
Definition Unit.cpp:11191
void StopAttackFaction(uint32 faction_id)
Definition Unit.cpp:13111
bool HasScheduledAIChange() const
Definition Unit.cpp:10225
void RemoveAreaAurasDueToLeaveWorld()
Definition Unit.cpp:4349
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition Unit.cpp:11034
bool CanModifyStats() const
Definition Unit.h:1548
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition Unit.cpp:2876
void RemoveCharmedBy(Unit *charmer)
Definition Unit.cpp:11946
void RemoveMovementForce(ObjectGuid id)
Definition Unit.cpp:14084
bool IsMounted() const
Definition Unit.h:912
Trinity::Containers::FlatSet< AuraApplication *, VisibleAuraSlotCompare > m_visibleAurasToUpdate
Definition Unit.h:1943
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:9543
void SetMaxHealth(uint64 val)
Definition Unit.cpp:10004
float GetMaxNegativeAuraModifier(AuraType auraType) const
Definition Unit.cpp:5084
float GetSpeedRate(UnitMoveType mtype) const
Definition Unit.h:1707
void SendPetAIReaction(ObjectGuid guid)
Definition Unit.cpp:10656
std::set< Unit * > AttackerSet
Definition Unit.h:637
virtual void SetTarget(ObjectGuid const &)=0
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3901
float GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5129
virtual uint32 GetPowerIndex(Powers power) const =0
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition Unit.cpp:10299
bool IsGuardian() const
Definition Unit.h:750
void UpdateStatBuffModForClient(Stats stat)
Definition Unit.cpp:5284
Unit * GetVictim() const
Definition Unit.h:726
void UpdatePetCombatState()
Definition Unit.cpp:9274
std::vector< Unit * > UnitVector
Definition Unit.h:639
uint32 GetExtraUnitMovementFlags() const
Definition Unit.h:1741
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition Unit.h:1881
int32 GetPower(Powers power) const
Definition Unit.cpp:10028
void RemoveWorldEffect(int32 worldEffectId)
Definition Unit.cpp:14564
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7583
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition Unit.cpp:9912
bool HasExtraUnitMovementFlag2(uint32 f) const
Definition Unit.h:1746
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition Unit.cpp:13083
bool IsUnderWater() const
Definition Unit.cpp:3336
void SetBattlePetCompanionGUID(ObjectGuid guid)
Definition Unit.h:1202
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition Unit.cpp:8942
void AddExtraAttacks(uint32 count)
Definition Unit.cpp:2372
void RemovePlayerFromVision(Player *player)
Definition Unit.cpp:6721
void SendFlightSplineSyncUpdate()
Definition Unit.cpp:638
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7855
float GetCreateStat(Stats stat) const
Definition Unit.h:1421
bool IsImmunedToAuraPeriodicTick(WorldObject const *caster, AuraEffect const *auraEffect) const
Definition Unit.cpp:7986
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition Unit.cpp:14274
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition Unit.cpp:10523
void UpdateSplinePosition()
Definition Unit.cpp:614
AreaTriggerRemoveReason
Definition Unit.h:1641
void SetOwnerGUID(ObjectGuid owner)
Definition Unit.cpp:6171
DeathState getDeathState() const
Definition Unit.h:1188
bool SetIgnoreMovementForces(bool ignore)
Definition Unit.cpp:14112
Unit * GetFirstControlled() const
Definition Unit.cpp:6599
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5099
void SetFacingTo(float const ori, bool force=true)
Definition Unit.cpp:13289
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:12141
bool m_aiLocked
Definition Unit.h:2025
void ApplyCastTimePercentMod(float val, bool apply)
Definition Unit.cpp:10992
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition Unit.cpp:5310
bool HealthAbovePct(float pct) const
Definition Unit.h:794
virtual float GetHealthMultiplierForTarget(WorldObject const *) const
Definition Unit.h:807
bool IsCritter() const
Definition Unit.h:1025
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1529
bool HealthBelowPct(float pct) const
Definition Unit.h:792
uint16 _movementAnimKitId
Definition Unit.h:2041
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:12958
bool CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading=false)
Definition Unit.cpp:12074
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
bool IsMagnet() const
Definition Unit.cpp:6573
std::unordered_set< AbstractFollower * > m_followingMe
Definition Unit.h:2027
virtual void Update(uint32 time) override
Definition Unit.cpp:423
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12177
void UnsummonAllTotems()
Definition Unit.cpp:6744
AuraApplication * _CreateAuraApplication(Aura *aura, uint32 effMask)
Definition Unit.cpp:3489
uint16 _meleeAnimKitId
Definition Unit.h:2042
void _UnregisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5462
GameObjectList m_gameObj
Definition Unit.h:1914
int32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 pdamage, DamageEffectType damagetype) const
Definition Unit.cpp:6994
void RemoveExtraUnitMovementFlag2(uint32 f)
Definition Unit.h:1745
AuraMap m_ownedAuras
Definition Unit.h:1924
std::array< float, MAX_STATS > m_createStats
Definition Unit.h:1898
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition Unit.cpp:3346
Unit(bool isWorldObject)
Definition Unit.cpp:309
bool IsInFeralForm() const
Definition Unit.cpp:9532
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5304
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:9956
std::unique_ptr< Movement::MoveSpline > movespline
Definition Unit.h:1838
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7280
void CalculateHoverHeight()
Definition Unit.cpp:14192
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition Unit.h:643
void RemoveUnitMovementFlag(uint32 f)
Definition Unit.h:1733
static std::vector< AuraEffect * > CopyAuraEffectList(AuraEffectList const &list)
Definition Unit.cpp:813
void RemoveBindSightAuras()
Definition Unit.cpp:6731
std::array< float, ADV_FLYING_MAX_SPEED_TYPE > m_advFlyingSpeed
Definition Unit.h:1946
void KnockbackFrom(Position const &origin, float speedXY, float speedZ, float angle=M_PI, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
Definition Unit.cpp:12491
void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
Definition Unit.cpp:12342
AuraApplicationMap m_appliedAuras
Definition Unit.h:1925
CharmInfo * InitCharmInfo()
Definition Unit.cpp:10379
void RemoveAllAttackers()
Definition Unit.cpp:6066
int32 SpellBaseAbsorbBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7621
void SetClass(uint8 classId)
Definition Unit.h:765
virtual bool CanSwim() const
Definition Unit.cpp:12944
virtual float GetNativeObjectScale() const
Definition Unit.h:1608
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition Unit.cpp:4960
void RemoveFromWorld() override
Definition Unit.cpp:10241
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId)
-------—Pet responses methods--------------—
Definition Unit.cpp:10632
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition Unit.cpp:2260
bool IsOnOceanFloor() const
Definition Unit.cpp:3341
void ScheduleAIChange()
Definition Unit.cpp:10196
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
Powers CalculateDisplayPowerType() const
Definition Unit.cpp:5762
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition Unit.h:747
std::array< float, MAX_MOVE_TYPE > m_speed_rate
Definition Unit.h:1945
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition Unit.cpp:9653
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition Unit.cpp:3735
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition Unit.cpp:5602
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:12756
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:701
bool isDying() const
Definition Unit.h:1186
void DoMeleeAttackIfReady()
Definition Unit.cpp:2174
float GetStat(Stats stat) const
Definition Unit.h:772
void SendMeleeAttackStop(Unit *victim=nullptr)
Definition Unit.cpp:2559
void RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition Unit.cpp:4302
void SendDurabilityLoss(Player *receiver, uint32 percent)
Definition Unit.cpp:11153
int32 SpellAbsorbBonusDone(Unit *victim, SpellInfo const *spellProto, int32 absorbamount, SpellEffectInfo const &spellEffectInfo, uint32 stack=1, AuraEffect const *aurEff=nullptr) const
Definition Unit.cpp:7626
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:8021
virtual float GetBlockPercent(uint8) const
Definition Unit.h:988
void RemoveAllAuras()
Definition Unit.cpp:4382
SpellHistory * GetSpellHistory()
Definition Unit.h:1498
std::array< float, MAX_ATTACK > m_modAttackSpeedPct
Definition Unit.h:1520
bool IsBlockCritical() const
Definition Unit.cpp:2577
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition Unit.cpp:1657
bool IsControlledByPlayer() const
Definition Unit.h:1214
Unit * m_charmer
Definition Unit.h:1950
void SetVisibleAura(AuraApplication *aurApp)
Definition Unit.cpp:717
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:9323
bool m_canDualWield
Definition Unit.h:715
bool HasBreakableByDamageCrowdControlAura(Unit const *excludeCasterChannel=nullptr) const
Definition Unit.cpp:778
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1208
void UpdateLiquidStatusOnPositionChange(Optional< LiquidData > const &newLiquidData)
Definition Unit.cpp:3353
bool HasAuraWithMechanic(uint64 mechanicMask) const
Definition Unit.cpp:4879
Minion * GetFirstMinion() const
Definition Unit.cpp:6215
UnitStandStateType GetStandState() const
Definition Unit.h:900
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7440
UnitAI * GetScheduledChangeAI()
Definition Unit.cpp:10217
uint16 _aiAnimKitId
Definition Unit.h:2040
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition Unit.cpp:4845
void DestroyForPlayer(Player const *target) const override
Definition Unit.cpp:14229
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition Unit.cpp:769
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:11773
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition Unit.cpp:8732
void SetPetGUID(ObjectGuid guid)
Definition Unit.h:1198
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13502
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:10568
void SetMaxPower(Powers power, int32 val)
Definition Unit.cpp:10083
void RemoveAllAreaTriggers(AreaTriggerRemoveReason reason=AreaTriggerRemoveReason::Default)
Definition Unit.cpp:5512
std::vector< std::pair< uint32, AuraApplication * > > AuraApplicationProcContainer
Definition Unit.h:657
virtual void setDeathState(DeathState s)
Definition Unit.cpp:9161
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1194
void GetPartyMembers(std::list< Unit * > &units)
Definition Unit.cpp:12196
void RemoveVehicleKit(bool onRemoveFromWorld=false)
Definition Unit.cpp:12090
ObjectGuid LastCharmerGUID
Definition Unit.h:1779
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition Unit.cpp:12533
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition Unit.cpp:14216
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2762
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1675
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition Unit.cpp:9586
CombatManager & GetCombatManager()
Definition Unit.h:1038
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:846
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition Unit.cpp:2387
void UpdateMovementForcesModMagnitude()
Definition Unit.cpp:14143
uint32 GetCreatureTypeMask() const
Definition Unit.cpp:9469
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition Unit.cpp:11116
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition Unit.cpp:4854
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4836
bool IsFlying() const
Definition Unit.h:1807
void SetCritterGUID(ObjectGuid guid)
Definition Unit.h:1200
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1295
void ClearBossEmotes(Optional< uint32 > zoneId={}, Player const *target=nullptr) const
Clears boss emotes frame.
Definition Unit.cpp:14432
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4294
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:701
void SetVignette(uint32 vignetteId)
Definition Unit.cpp:14576
void InitStatBuffMods()
Definition Unit.cpp:5209
int32 m_procDeep
Definition Unit.h:1907
void ClearDiminishings()
Definition Unit.cpp:9445
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:9347
bool IsUninteractible() const
Definition Unit.h:1052
std::vector< AreaTrigger * > GetAreaTriggers(uint32 spellId) const
Definition Unit.cpp:5475
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition Unit.cpp:5347
std::array< uint32, MAX_ATTACK > m_attackTimer
Definition Unit.h:1521
bool IsServiceProvider() const
Definition Unit.cpp:8485
MountCapabilityEntry const * GetMountCapability(uint32 mountType) const
Definition Unit.cpp:8362
void SetVisibleAuraUpdate(AuraApplication *aurApp)
Definition Unit.cpp:731
bool IsTotem() const
Definition Unit.h:753
CombatManager m_combatManager
Definition Unit.h:2016
void ChangeSeat(int8 seatId, bool next=true)
Definition Unit.cpp:12803
void SetInFront(WorldObject const *target)
Definition Unit.cpp:13283
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition Unit.cpp:9428
AuraStateAurasMap m_auraStateAuras
Definition Unit.h:1933
int32 GetResistance(SpellSchools school) const
Definition Unit.h:781
AuraList & GetSingleCastAuras()
Definition Unit.h:1344
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition Unit.cpp:8752
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4646
Vehicle * GetVehicleKit() const
Definition Unit.h:1782
bool CanCastSpellWhileMoving(SpellInfo const *spellInfo) const
Definition Unit.cpp:3282
void PushAI(UnitAI *newAI)
Definition Unit.cpp:10165
float m_modSpellHitChance
Definition Unit.h:1516
void ValidateAttackersAndOwnTarget()
Definition Unit.cpp:5994
Guardian * GetGuardianPet() const
Definition Unit.cpp:6231
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:665
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4730
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition Unit.cpp:14324
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:5570
virtual bool IsEngaged() const
Definition Unit.h:1034
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const &familyFlag, ObjectGuid casterGUID)
Definition Unit.cpp:4276
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition Unit.cpp:3531
void DeMorph()
Definition Unit.cpp:3382
void RemoveAllMinionsByEntry(uint32 entry)
Definition Unit.cpp:6430
AuraMap & GetOwnedAuras()
Definition Unit.h:1285
void UpdateAllDamagePctDoneMods()
Definition Unit.cpp:9815
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7084
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition Unit.cpp:14347
void ClearChannelObjects()
Definition Unit.cpp:3076
bool IsFalling() const
Definition Unit.cpp:12939
bool AttackStop()
Definition Unit.cpp:5965
std::array< float, MAX_STATS > m_floatStatNegBuff
Definition Unit.h:1900
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3254
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, SpellInfo const *spellInfo) const override
Definition Unit.cpp:12428
void RemoveAurasOnEvade()
Definition Unit.cpp:4443
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9635
float SpellAbsorbPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7692
void SetShapeshiftForm(ShapeshiftForm form)
Definition Unit.cpp:9494
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition Unit.cpp:2942
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12158
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition Unit.cpp:11225
bool m_cleanupDone
Definition Unit.h:2033
SharedVisionList m_sharedVision
Definition Unit.h:1953
void SetMeleeAnimKitId(uint16 animKitId)
Definition Unit.cpp:11208
float GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5149
EnumFlag< SpellAuraInterruptFlags > m_interruptMask
Definition Unit.h:1934
std::array< AuraEffectList, TOTAL_AURAS > m_modAuras
Definition Unit.h:1930
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:7328
ObjectGuid GetTarget() const
Definition Unit.h:1831
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition Unit.h:2038
void SetPowerType(Powers power, bool sendUpdate=true, bool onInit=false)
Definition Unit.cpp:5697
uint8 GetLevel() const
Definition Unit.h:757
void SetMountDisplayId(uint32 mountDisplayId)
Definition Unit.h:914
uint8 GetRace() const
Definition Unit.h:761
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange=false)
Definition Unit.cpp:4159
virtual void SetDisplayId(uint32 displayId, bool setNative=false)
Definition Unit.cpp:10779
void TriggerAuraHeartbeat()
Definition Unit.cpp:517
void RemoveCharmAuras()
Definition Unit.cpp:6736
bool IsInCombat() const
Definition Unit.h:1058
bool IsWalking() const
Definition Unit.h:1150
void SetWildBattlePetLevel(uint32 wildBattlePetLevel)
Definition Unit.h:1271
bool IsSitState() const
Definition Unit.cpp:10716
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition Unit.cpp:3159
void RemoveVisibleAuraUpdate(AuraApplication *aurApp)
Definition Unit.cpp:736
GetCastSpellInfoResult GetCastSpellInfo(SpellInfo const *spellInfo) const
Definition Unit.h:1480
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition Unit.cpp:12539
void AddWorldEffect(int32 worldEffectId)
Definition Unit.cpp:14559
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:847
void SetAIAnimKitId(uint16 animKitId)
Definition Unit.cpp:11174
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:14366
Unit * GetDemonCreator() const
Definition Unit.cpp:6192
Player * m_playerMovingMe
Definition Unit.h:1949
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer, int32 stolenCharges=1)
Definition Unit.cpp:4035
AreaTrigger * GetAreaTrigger(uint32 spellId) const
Definition Unit.cpp:5469
uint32 GetDamageImmunityMask() const
Definition Unit.cpp:7825
Player * GetControllingPlayer() const
Definition Unit.cpp:6202
float GetWeaponProcChance() const
Definition Unit.cpp:8259
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition Unit.cpp:3387
ObjectGuid GetPetGUID() const
Definition Unit.h:1197
void RemoveChannelObject(ObjectGuid guid)
Definition Unit.cpp:3069
void UpdateStatBuffMod(Stats stat)
Definition Unit.cpp:5219
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12835
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition Unit.h:1938
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:6040
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1466
bool BuildPacket(WorldPacket *packet)
Unit * GetBase() const
Definition Vehicle.h:49
Vehicle * RemovePassenger(WorldObject *passenger) override
Removes the passenger from the vehicle.
Definition Vehicle.cpp:513
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:121
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition Vehicle.cpp:579
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition Vehicle.h:67
std::string GetDebugInfo() const
Definition Vehicle.cpp:997
SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const
Gets the next empty seat based on current seat.
Definition Vehicle.cpp:326
VehicleSeatAddon const * GetSeatAddonForSeatOfPassenger(Unit const *passenger) const
Gets the vehicle seat addon data for the seat of a passenger.
Definition Vehicle.cpp:370
Milliseconds GetDespawnDelay()
Definition Vehicle.cpp:980
void InstallAllAccessories(bool evading)
Definition Vehicle.cpp:97
bool AddVehiclePassenger(Unit *unit, int8 seatId=-1)
Definition Vehicle.cpp:442
constexpr uint32 GetMapId() const
Definition Position.h:216
int8 GetTransSeat() const
Definition Object.h:544
bool InSamePhase(PhaseShift const &phaseShift) const
Definition Object.h:314
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition Object.cpp:476
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1094
Map * GetMap() const
Definition Object.h:411
ZLiquidStatus GetLiquidStatus() const
Definition Object.h:337
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:711
void AddToWorld() override
Definition Object.cpp:365
virtual bool IsAlwaysVisibleFor(WorldObject const *seer) const
Definition Object.h:606
Unit * GetCharmerOrOwner() const
Definition Object.cpp:1603
void RemoveFromWorld() override
Definition Object.cpp:371
InstanceScript * GetInstanceScript() const
Definition Object.cpp:396
virtual uint8 GetLevelForTarget(WorldObject const *) const
Definition Object.h:385
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:1991
Unit * GetCharmerOrOwnerOrSelf() const
Definition Object.cpp:1613
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition Object.cpp:1133
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
std::string GetDebugInfo() const override
Definition Object.cpp:3136
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2324
virtual bool IsAlwaysDetectableFor(WorldObject const *seer) const
Definition Object.h:609
bool IsHostileTo(WorldObject const *target) const
Definition Object.cpp:2181
PhaseShift & GetPhaseShift()
Definition Object.h:310
Unit * GetOwner() const
Definition Object.cpp:1598
ZoneScript * GetZoneScript() const
Definition Object.h:417
TransportBase * GetTransport() const
Definition Object.h:537
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect, bool canImmune) const
Definition Object.cpp:1942
void setActive(bool isActiveObject)
Definition Object.cpp:276
float GetFloorZ() const
Definition Object.cpp:3106
std::string const & GetName() const
Definition Object.h:342
virtual void Heartbeat()
Definition Object.h:611
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:535
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition Object.cpp:353
Player * GetSpellModOwner() const
Definition Object.cpp:1641
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:1621
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:501
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition Object.cpp:257
void AddToNotify(uint16 f)
Definition Object.h:519
EventProcessor m_Events
Definition Object.h:561
float GetVisibilityRange() const
Definition Object.cpp:787
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition Object.cpp:2632
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:432
uint32 GetAreaId() const
Definition Object.h:333
uint32 GetZoneId() const
Definition Object.h:332
MovementInfo m_movementInfo
Definition Object.h:548
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition Object.h:406
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2186
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:469
virtual void Update(uint32 diff)
Definition Object.cpp:245
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition Object.cpp:2000
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3047
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:335
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
WorldPacket const * Write() override
std::vector< int32 > SpellVisualKitIDs
WorldPacket const * Write() override
Optional< Spells::ContentTuningParams > ContentTuning
std::vector< PeriodicAuraLogEffect > Effects
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
WorldPacket const * Write() override
TaggedPosition< Position::XY > Direction
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
TaggedPosition< Position::XYZ > Pos
WorldPacket const * Write() override
::MovementForces::Container const * MovementForces
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition Packet.h:38
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::XYZ > TargetPosition
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.
#define sWorld
Definition World.h:916
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition World.h:313
@ CONFIG_EXPANSION
Definition World.h:306
@ RATE_POWER_RAGE_INCOME
Definition World.h:449
@ RATE_DURABILITY_LOSS_DAMAGE
Definition World.h:519
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition World.h:518
@ CONFIG_LISTEN_RANGE_YELL
Definition World.h:211
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:209
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition World.h:210
@ CONFIG_DURABILITY_LOSS_IN_PVP
Definition World.h:105
TimePoint Now()
Current chrono steady_clock time point.
Definition GameTime.cpp:67
time_t GetGameTime()
Definition GameTime.cpp:52
uint32 GetGameTimeMS()
Definition GameTime.cpp:57
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 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)
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
constexpr auto MapValue
Definition MapUtils.h:77
bool IsValidMapCoord(float c)
UpdateFieldFlag
Definition UpdateField.h:37
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
Definition SpellAuras.h:127
ObjectGuid CastItemGUID
Definition SpellAuras.h:130
AuraCreateInfo & SetCaster(Unit *caster)
Definition SpellAuras.h:115
uint32 CastItemId
Definition SpellAuras.h:131
int32 CastItemLevel
Definition SpellAuras.h:132
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
Definition SpellAuras.h:114
uint32 GetAuraEffectMask() const
Definition SpellAuras.h:125
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:124
AuraCreateInfo & SetBaseAmount(SpellEffectValue const *bp)
Definition SpellAuras.h:116
SpellEffectValue const * BaseAmount
Definition SpellAuras.h:129
AuraCreateInfo & SetStackAmount(int32 stackAmount)
Definition SpellAuras.h:120
bool ResetPeriodicTimer
Definition SpellAuras.h:135
WeaponAttackType AttackType
Definition Unit.h:546
ProcFlagsInit ProcAttacker
Definition Unit.h:547
uint32 DamageSchoolMask
Definition Unit.h:535
Unit * Target
Definition Unit.h:534
uint32 TargetState
Definition Unit.h:542
MeleeHitOutcome HitOutCome
Definition Unit.h:550
Unit * Attacker
Definition Unit.h:533
uint32 Damage
Definition Unit.h:536
uint32 RageGained
Definition Unit.h:543
uint32 Blocked
Definition Unit.h:540
uint32 Resist
Definition Unit.h:539
uint32 CleanDamage
Definition Unit.h:549
uint32 HitInfo
Definition Unit.h:541
uint32 Absorb
Definition Unit.h:538
uint32 OriginalDamage
Definition Unit.h:537
ProcFlagsInit ProcVictim
Definition Unit.h:548
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
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:13232
float _stayY
Definition CharmInfo.h:151
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13222
bool IsCommandAttack()
Definition Unit.cpp:13217
bool _isAtStay
Definition CharmInfo.h:147
void InitPossessCreateSpells()
Definition CharmInfo.cpp:74
void SetIsAtStay(bool val)
Definition Unit.cpp:13253
bool IsFollowing()
Definition Unit.cpp:13268
float _stayX
Definition CharmInfo.h:150
void SetPetNumber(uint32 petnumber, bool statwindow)
float _stayZ
Definition CharmInfo.h:152
bool IsReturning()
Definition Unit.cpp:13278
void SetIsFollowing(bool val)
Definition Unit.cpp:13263
bool _isCommandFollow
Definition CharmInfo.h:146
void SetIsReturning(bool val)
Definition Unit.cpp:13273
void InitCharmCreateSpells()
bool IsAtStay()
Definition Unit.cpp:13258
bool _isFollowing
Definition CharmInfo.h:148
bool _isCommandAttack
Definition CharmInfo.h:145
void GetStayPosition(float &x, float &y, float &z)
Definition Unit.cpp:13246
bool IsCommandFollow()
Definition Unit.cpp:13227
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13212
bool _isReturning
Definition CharmInfo.h:149
Unit * _unit
Definition CharmInfo.h:136
EnumFlag< ChrRacesFlag > GetFlags() const
uint32 absorbed_damage
Definition Unit.h:411
WeaponAttackType attackType
Definition Unit.h:414
EnumFlag< CreatureModelDataFlags > GetFlags() const
uint32 CreatureDisplayID
DeclinedName()=default
uint32 hitCount
Definition Unit.h:381
uint32 hitTime
Definition Unit.h:380
uint16 stack
Definition Unit.h:379
InventoryType GetInventoryType() const
uint32 GetSubClass() const
uint32 GetDelay() const
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
TaggedPosition< Position::XYZ > Origin
ObjectGuid ID
TaggedPosition< Position::XYZ > Direction
ObjectGuid guid
void SetFallTime(uint32 fallTime)
void RemoveMovementFlag(uint32 flag)
struct MovementInfo::TransportInfo transport
bool HasMovementFlag(uint32 flag) const
Position pos
Optional< LiquidData > liquidInfo
Definition MapDefines.h:173
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
constexpr Position()
Definition Position.h:31
float m_positionZ
Definition Position.h:66
constexpr float GetPositionY() const
Definition Position.h:88
std::string ToString() const
Definition Position.cpp:202
float m_positionX
Definition Position.h:64
float m_positionY
Definition Position.h:65
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:173
float GetAbsoluteAngle(float x, float y) const
Definition Position.h:136
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
constexpr void Relocate(float x, float y)
Definition Position.h:74
constexpr Position GetPosition() const
Definition Position.h:95
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition Position.h:155
void RelocateOffset(Position const &offset)
Definition Position.cpp:34
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
EnumFlag< PowerTypeFlags > GetFlags() const
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, SpellInfo const *_spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId=ObjectGuid::Empty)
Definition Unit.cpp:303
ObjectGuid castId
Definition Unit.h:560
uint32 preHitHealth
Definition Unit.h:575
SpellCastVisual SpellVisual
Definition Unit.h:562
Unit * attacker
Definition Unit.h:559
uint32 schoolMask
Definition Unit.h:565
SpellInfo const * Spell
Definition Unit.h:561
uint32 cleanDamage
Definition Unit.h:573
uint32 originalDamage
Definition Unit.h:564
uint32 reflectingSpellId
Definition Unit.h:570
AuraEffect const * auraEff
Definition Unit.h:583
EnumFlag< SpellShapeshiftFormFlags > GetFlags() const
EnumFlag< SummonPropertiesFlags > GetFlags() const
WorldLocation Location
Definition Player.h:1226
Optional< ObjectGuid > TransportGuid
Definition Player.h:1227
UpdateFieldArray< std::string, 5, 0, 1 > Name
UpdateField< uint8, 64, 85 > SheatheState
UpdateField< uint32, 32, 51 > RangedAttackRoundBaseTime
UpdateFieldArray< int32, 10, 137, 138 > Power
UpdateField< float, 32, 58 > NativeXDisplayScale
UpdateFieldArray< int32, 10, 137, 148 > MaxPower
UpdateField< uint8, 32, 33 > CreatureType
DynamicUpdateField< int32, 0, 4 > WorldEffects
UpdateField< int32, 96, 125 > FlightCapabilityID
UpdateFieldArray< uint32, 2, 182, 183 > AttackRoundBaseTime
UpdateField< uint32, 128, 132 > CurrentAreaID
UpdateField< uint8, 64, 69 > AnimTier
DynamicUpdateField< ObjectGuid, 0, 5 > ChannelObjects
UpdateField< ObjectGuid, 0, 18 > SummonedBy
UpdateField< uint8, 64, 88 > ShapeshiftForm
UpdateField< int32, 32, 57 > NativeDisplayID
UpdateFieldArray< UF::VisibleItem, 3, 178, 179 > VirtualItems
UpdateField< uint8, 32, 34 > DisplayPower
UpdateField< ObjectGuid, 0, 17 > CharmedBy
UpdateField< float, 64, 77 > ModHaste
UpdateField< float, 64, 76 > ModSpellHaste
UpdateField< int32, 32, 38 > Level
UpdateField< uint32, 0, 8 > NpcFlags2
UpdateField< uint8, 64, 66 > StandState
UpdateField< float, 64, 78 > ModRangedHaste
UpdateField< int32, 0, 6 > DisplayID
UpdateField< int64, 32, 36 > Health
UpdateField< int64, 32, 37 > MaxHealth
UpdateFieldArray< int32, 5, 185, 191 > StatPosBuff
UpdateField< float, 64, 74 > ModCastingSpeed
UpdateField< float, 64, 79 > ModHasteRegen
UpdateField< float, 32, 54 > DisplayScale
UpdateField< ObjectGuid, 0, 14 > Charm
UpdateFieldArray< int32, 5, 185, 196 > StatNegBuff
UpdateField< uint32, 0, 7 > NpcFlags
UpdateField< uint32, 32, 50 > AuraState
UpdateField< uint16, 0, 7 > ItemVisual
UpdateField< int32, 0, 3 > ItemID
UpdateField< uint16, 0, 6 > ItemAppearanceModID
std::array< uint32, 5 > VisitedSpells
Definition Unit.h:1472
bool AddSpell(uint32 spellId)
Definition Unit.cpp:14448
bool operator()(AuraApplication *left, AuraApplication *right) const
Definition Unit.cpp:14527
VehicleExitParameters ExitParameter
Optional< Spells::ContentTuningParams > ContentTuning
void Add(EntityFragment fragment, bool update, void const *data=nullptr)